In JavaScript, if you take a function returned by Function.prototype.bind and then call it with call, apply, or bind again, which this value wins?
answer
- the first decision is the permanent one
- exotic object stores target and receiver
- later thisArg silently discarded
- arguments still accumulate, receiver does not
basics
~20 sThe first bind wins. bind produces a hard-bound function whose receiver is permanent, so a later call, apply, or bind cannot override it — the extra thisArg is silently ignored, though extra arguments are still passed through.
solid answer
~40 s`bind` returns a *bound function exotic object* that internally stores the target function, the bound `this`, and any bound arguments. When that object is invoked, it always calls the target with the stored receiver, no matter how the invocation happened. So `f.bind(a).call(b)` runs with `this === a`, and `f.bind(a).bind(b)()` also runs with `this === a` — the second bind wraps the already-bound function, whose receiver it cannot reach. Nothing throws; the ignored `thisArg` just has no effect, which is what makes this a nasty debugging surprise. Arguments behave differently: bound arguments are prepended, and later arguments are appended after them, so partial application still composes. The returned function also gets a `name` of `"bound "` plus the target's name and a `length` reduced by the number of bound arguments.
code
javascript · 13 linesfunction who() { return this.tag; }
const a = { tag: 'A' };
const b = { tag: 'B' };
const boundA = who.bind(a);
console.log(boundA()); // 'A'
console.log(boundA.call(b)); // 'A' - ignored
console.log(boundA.apply(b)); // 'A' - ignored
console.log(boundA.bind(b)()); // 'A' - ignored
const holder = { tag: 'C', m: boundA };
console.log(holder.m()); // 'A' - even as a methodgo deeper
Remember the headline rule: once a function has been bound, its this is fixed and a later call or apply cannot change it. Say that the extra receiver is ignored rather than rejected.
Explain the mechanism — the returned object stores target, receiver and arguments, and the innermost bound layer is the one that decides — and note that bound arguments still accumulate.
Point out that the override fails silently, so a wrongly-bound callback shows up as wrong data rather than an exception, and describe how you would trace it back through the layer that bound it.
Own the API contract: decide deliberately whether your library hands out hard-bound functions (safe against receiver loss, impossible to retarget) or unbound ones, and document which, because callers cannot undo the choice.
## What bind actually produces `Function.prototype.bind` does not return an ordinary function that happens to call the original. It returns a *bound function exotic object* — a special kind of function object defined by the specification, which internally records three things: - the **target function** it will ultimately invoke, - the **bound this** value you passed as the first argument, - the **bound arguments** you passed after it (possibly none). When that object is called, the specification ignores whatever receiver the call site supplies and invokes the target with the stored receiver instead. That is what people mean by *hard binding*: the receiver is baked in, not merely defaulted. ```js function who() { return this.tag; } const a = { tag: 'A' }; const b = { tag: 'B' }; const boundA = who.bind(a); boundA(); // 'A' boundA.call(b); // 'A' - call's thisArg is ignored boundA.apply(b); // 'A' - so is apply's boundA.bind(b)(); // 'A' - and so is a second bind ({ tag: 'C', m: boundA }).m(); // 'A' - even as a method ``` ## Why re-binding cannot work The second `bind` is not doing anything strange: it faithfully creates a new bound function whose target is `boundA` and whose bound receiver is `b`. When you invoke it, it calls `boundA` with `this === b`. But `boundA` is itself a bound function, and *it* ignores the receiver it is called with. The receiver `b` is delivered correctly and then discarded one layer down. Hard binding wins because the inner layer is the one that finally decides. The important practical consequence is that this failure is **silent**. No error, no warning — the code simply operates on the wrong object. If a helper receives a callback that some other layer already bound, any attempt by that helper to control the receiver quietly does nothing. ## Arguments are not ignored Only the receiver is fixed. Bound arguments are *prepended* to the arguments of the eventual call: ```js function join(sep, ...parts) { return parts.join(sep); } const dashed = join.bind(null, '-'); dashed('a', 'b', 'c'); // 'a-b-c' ``` So re-binding still usefully accumulates arguments even though it cannot change `this`: ```js const step1 = join.bind(null, '-'); const step2 = step1.bind({}, 'x'); // receiver ignored, 'x' appended to bound args step2('y'); // 'x-y' ``` ## Observable properties of the bound function The returned function is a distinct object with its own metadata: ```js function greet(a, b, c) {} const g = greet.bind(null, 1); g.name; // 'bound greet' g.length; // 2 - original 3 minus 1 bound argument g === greet.bind(null, 1); // false - every call makes a new object ``` `name` is `"bound "` prefixed to the target's name (bind it twice and you get `"bound bound greet"`), and `length` is the target's declared arity minus the number of bound arguments, clamped at zero. A bound function also has **no own `prototype` property**, because it never needs one — construction delegates to the target. The identity point matters in practice: `bind` allocates a fresh function object on every call, so two separately-bound copies of the same method are never `===` to each other. Any code that stores a function and later looks it up by identity must keep hold of the exact bound instance it stored, not re-bind and hope for a match. ## Where this shows up An interviewer usually probes this after you have said "just use bind" as a fix for a lost receiver. The follow-up is: what if a *caller* now wants a different receiver? The honest answer is that they cannot have one, and that this is a feature — hard binding exists precisely so that a function handed to unknown code keeps its receiver. If you need flexibility instead, do not bind: hand out a wrapper that forwards `this` explicitly, or expose the raw method and let each call site choose. One genuine exception exists: applying `new` to a bound function does *not* use the bound receiver, because construction creates its own object. That single case is the only way the stored `this` is bypassed.
- How do the name and length of a bound function relate to the target's?`name` is the string `"bound "` followed by the target's name, so binding twice yields `"bound bound f"`. `length` is the target's declared arity minus the number of bound arguments, clamped at zero — `f(a, b, c)` bound with one argument reports `length` 2. Both are informational; nothing in the language enforces them at call time.
- Does a bound function have its own prototype property?No. Bound functions are exotic objects created without an own `prototype`, because they never need one — if the target is constructible, construction is delegated to the target and uses the target's `prototype`. So `boundFn.prototype` is `undefined` even when `target.prototype` is a normal object.
- If hard binding is irreversible, how would you hand out a function whose receiver a caller can still choose?Do not bind it. Either expose the method itself and let each call site use ordinary method-call syntax or `call`, or hand out a plain wrapper function that forwards its own receiver, such as `function (...args) { return target.apply(this, args); }`. That wrapper takes its `this` from its call site, so `call` and `apply` on it work normally.
saying these in an interview costs you the question
- Thinks a second bind rebinds the receiver
- Expects call on a bound function to throw
- Believes bind mutates the target function
- Says bound arguments are also discarded
- Assumes two bind calls yield the same function object