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: obj2

Why 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.

Specification references

JavaScript Code EditorDirectly edit or paste custom code
Step 0 of 0
StepSpaceRun
Press → (Step) or Space (Run)
Phase 1: Compilation(Hoisting & Memory Setup)
Phase 2: Execution(Line-by-line Evaluation)
Execution Step Breakdown

Press "→" / click "▶" to step line-by-line, or press "Space" / click "▶ Run" for auto-play.