How does `Function.prototype.bind` let you partially apply a JavaScript function, and what happens to arguments passed later to the bound function?
answer
- extras after the first argument
- pinned values go in front
- later arguments are appended
- left-to-right only, no placeholders
- returns a new function, original untouched
basics
~20 sEvery argument after bind's first is stored and prepended to each later call, so greet.bind(null, 'Hi') returns a function that always supplies 'Hi' first and appends whatever the caller passes. Only leading arguments can be pinned this way.
solid answer
~50 s`bind` takes a receiver as its first argument and then any number of extra arguments. Those extras are remembered by the function it returns, which on each invocation calls the original with the pinned arguments first and the call-site arguments appended after them — that is partial application straight from the standard library, no helper needed. For pure argument pinning people pass `null` or `undefined` as the first argument, since only the receiver slot is being ignored. Two observable details are worth knowing: the returned function's `length` is the original's `length` minus the number of pinned arguments (floored at zero), and its `name` becomes `"bound "` plus the original name, which shows up in stack traces. The limitation is positional: `bind` fills slots strictly from the left, so there is no way to pin only the second parameter.
code
javascript · 10 linesfunction greet(greeting, punctuation, name) {
return `${greeting}, ${name}${punctuation}`;
}
const hi = greet.bind(null, 'Hi', '!');
console.log(hi('Ada')); // "Hi, Ada!"
console.log(hi.length); // 1 (3 declared - 2 pinned)
console.log(hi.name); // "bound greet"
console.log(greet('Yo', '?', 'Ada')); // original is untouchedgo deeper
Know that everything after bind's first argument is pre-filled from the left and that later arguments are appended, and remember that bind returns a new function you must keep.
Explain the observable effects — length reduced by the number of pinned arguments, name prefixed with "bound ", cumulative behaviour when binding twice — and when a closure reads better.
Show why left-only pinning drives parameter-order design, and recognise pre-bound helpers in stack traces when diagnosing where a wrong argument entered.
Own the convention question: whether shared utilities standardise on bind, closures, or a curry helper determines how discoverable specialised functions are across a large codebase.
## The signature ```js fn.bind(thisArg, ...boundArgs) ``` `bind` returns a **new** function — the original is untouched and still callable normally. The first argument is the receiver the bound function will use; every argument after it is stored for later. When the bound function is invoked, the engine calls the target with `boundArgs` first, then whatever the caller supplied. ```js function greet(greeting, punctuation, name) { return `${greeting}, ${name}${punctuation}`; } const hi = greet.bind(null, 'Hi', '!'); hi('Ada'); // "Hi, Ada!" hi('Grace'); // "Hi, Grace!" ``` When your only goal is pinning arguments, the receiver slot still has to be filled, and `null` (or `undefined`) is the conventional filler. ## Arguments arrive appended, never merged There is no matching or placeholder logic. The pinned list and the call-site list are simply concatenated in that order: ```js const shout = greet.bind(null, 'HEY'); shout('!!', 'Ada'); // "HEY, Ada!!" — '!!' lands in `punctuation` ``` That concatenation is why partial application via `bind` works only from the left. If the argument you want to fix is the third parameter, `bind` cannot help; you write a closure instead: ```js const withName = (name) => (greeting, punctuation) => greet(greeting, punctuation, name); ``` This is precisely why libraries designed for partial application put configuration parameters first and the varying data last. ## Observable properties of the returned function ```js function f(a, b, c) {} const g = f.bind(null, 1); g.length; // 2 — 3 declared minus 1 pinned g.name; // "bound f" const h = g.bind(null, 2, 3, 4); h.length; // 0 — never negative h.name; // "bound bound f" ``` `length` is computed as the target's `length` minus the number of bound arguments, floored at `0`. `name` gains one `"bound "` prefix per binding, which makes deeply pre-configured helpers recognisable in a stack trace. Binding is also cumulative for arguments: the second `bind` above appends to what the first already pinned. One consequence of `length` shrinking: a partially applied function handed to an arity-driven helper (a `curry` that reads `fn.length`, for instance) reports the *remaining* arity, which is usually exactly what you want. ## When to prefer a closure `bind` is concise and needs no helper, but a plain arrow function is often clearer and is the only option when the argument you want to fix is not leftmost: ```js const hi2 = (name) => greet('Hi', '!', name); ``` The closure version also survives refactors that reorder parameters more visibly — you get an obviously wrong argument rather than a silently shifted one. `bind`'s advantages are that it is built in, that it produces a function with a meaningful `name`, and that it can pin arguments to a function you received rather than one you wrote. ## Common mistakes Forgetting the receiver argument entirely is the classic one: `greet.bind('Hi')` pins **nothing** — it sets the receiver to `'Hi'` and leaves all three parameters outstanding, so `greet.bind('Hi')('Hello', '!', 'Ada')` still works normally and the intended pinning silently did not happen. The other frequent error is expecting `bind` to mutate the original function; it does not, and ignoring the return value means nothing was accomplished.
- How would you pin only the *second* parameter of a three-parameter function?Not with `bind` — it fills slots strictly left to right. Write a closure that places the fixed value in the right position: `const g = (a, c) => f(a, FIXED, c)`. If this need keeps coming up, the real fix is the signature: reorder the parameters so the ones you specialise come first, which is the same discipline that makes currying useful.
- What does `f.bind(null)` with no extra arguments accomplish for argument handling?Nothing for arguments — it pins none, so the returned function has the same arity and forwards every call-site argument unchanged. It only fixes the receiver, so as a partial-application move it is a no-op, and code written that way usually reflects a misunderstanding of where `bind`'s argument list starts.
- Does binding a function twice combine the pinned arguments or replace them?It combines them. Each `bind` wraps the previous result, so the outer binding's arguments are prepended to the inner one's already-pinned list, and call-site arguments still land last. The `length` shrinks cumulatively and the `name` picks up another `"bound "` prefix, which is a useful tell when reading a stack trace.
saying these in an interview costs you the question
- Thinks bind only sets the receiver and cannot pre-fill arguments
- Forgets the first argument is the receiver, so nothing actually gets pinned
- Says bind modifies the original function in place
- Expects later arguments to fill unpinned slots by position rather than appending
- Claims bind can pin an argument anywhere in the parameter list