Question 26 / 31
Why do these logs run immediately instead of after the delay?
Topic: this bindingDifficulty: Advanced
Function arguments are evaluated before the call that receives them runs — so a `.call()` written as an argument executes right away, not later.
Solve it with the execution visualizerStep through every binding, function call, and console output below.Predict the output
Predict the output. The callback is written inline with .call(obj1) attached — does setTimeout still wait 0ms before it runs?
var obj1 = { a: 1 };
var obj2 = {
a: 2,
foo1: function () {
console.log(this.a);
},
foo2: function () {
setTimeout(function () {
console.log(this);
console.log(this.a);
}.call(obj1), 0);
}
};
var a = 3;
obj2.foo1();
obj2.foo2();Reveal the answer and explanation
Expected output
2
{ a: 1 }
1Why this happens
obj2.foo1() is a plain member call: implicit binding sets this to obj2, so this.a reads 2 immediately.
obj2.foo2() runs next. Before setTimeout itself can be invoked, its arguments must be evaluated per EvaluateCall — and the first argument here is not a bare function, it is the CallExpression function () {...}.call(obj1). Evaluating that argument means invoking it right now, synchronously, with this explicitly forced to obj1, which is why console.log(this) and console.log(this.a) run immediately and print { a: 1 } and 1 — with no delay at all.
That inner call has no return statement, so it evaluates to undefined, and that is the actual value setTimeout receives as its first argument. A non-function handler never fires later, so nothing else happens once the delay elapses.
What this question tests
- argument expressions are evaluated before the call they belong to actually runs
- a .call()/.apply() expression written as an argument executes immediately, wherever it appears syntactically
- setTimeout only ever schedules whatever value its first argument evaluates to — here, that value is undefined, not a function
Runtime assumptions
This function's return value being undefined (no explicit return) is what makes setTimeout a no-op afterward; every standard timer implementation treats a non-callable handler as inert.