Question 23 / 31
Does .call() at the end of a chain bind the outer call or just the inner one?
Topic: this bindingDifficulty: Advanced
call attaches only to the specific function value it is invoked on, immediately before that invocation.
Solve it with the execution visualizerStep through every binding, function call, and console output below.Predict the output
Predict all three pairs of lines. Each line calls foo, then immediately invokes whatever foo returns — trace this for each call separately.
var obj = {
a: 'obj',
foo: function () {
console.log('foo:', this.a);
return function () {
console.log('inner:', this.a);
};
}
};
var a = 'window';
var obj2 = { a: 'obj2' };
obj.foo()();
obj.foo.call(obj2)();
obj.foo().call(obj2);Reveal the answer and explanation
Expected output
foo: obj
inner: window
foo: obj2
inner: window
foo: obj
inner: obj2Why this happens
obj.foo()() first calls foo as obj.foo() — implicit binding, so foo: obj. That call returns a plain inner function, which is then invoked bare with no receiver, so inner: window (default binding).
obj.foo.call(obj2)() explicitly binds foo's own this to obj2 for that first invocation, so foo: obj2. The returned inner function is still invoked as a separate, receiver-less call, so inner: window again — the earlier .call(obj2) has no effect on it.
obj.foo().call(obj2) calls foo implicitly first (foo: obj, unaffected by anything that comes later), and only then chains .call(obj2) onto the returned inner function, forcing inner: obj2 for that specific invocation.
What this question tests
- call/apply/bind bind this only for the exact function value they are called on
- a returned closure is a separate function value with its own, independently decided this
- reading the call chain left to right shows exactly which invocation each .call() attaches to
Runtime assumptions
Assumes a classic sloppy-mode script; the returned inner function is an ordinary function, so it is still subject to default binding when invoked bare.