Question 24 / 31
How do a captured closure variable and this evolve independently here?
Topic: ClosuresDifficulty: Advanced
The IIFE's parameter num is captured by closure, while every this is re-resolved fresh at each call site — including for the global num binding itself.
Solve it with the execution visualizerStep through every binding, function call, and console output below.Predict the output
Predict all three lines. Track the closure-captured num separately from this.num, and note that a global var is also a property of the global object.
var num = 10;
var obj = { num: 20 };
obj.fn = (function (num) {
this.num = num * 3;
num++;
return function (n) {
this.num += n;
num++;
console.log(num);
};
})(obj.num);
var fn = obj.fn;
fn(5);
obj.fn(10);
console.log(num, obj.num);Reveal the answer and explanation
Expected output
22
23
65 30Why this happens
The IIFE runs immediately as a receiver-less call, so its this is the global object; this.num = num * 3 sets the global num property (also readable as the outer var num) to 60. The closure's own num parameter, started at 20, is then incremented to 21 by num++ before the inner function is returned and stored as obj.fn.
fn(5) invokes that returned function through the bare variable fn, so default binding applies: this is the global object. this.num += 5 makes the global num 65, the closure's num becomes 22, and console.log(num) reads the closure's num, logging 22.
obj.fn(10) invokes the same function through implicit binding instead, so this is obj: this.num += 10 makes obj.num become 30, the closure's num becomes 23, and that line logs 23. The final console.log(num, obj.num) reads the outer num — which is the same global-object property this.num already mutated to 65 — and obj.num, now 30, printing "65 30".
What this question tests
- a closure variable is captured once and evolves independently of this
- this is re-decided at every call: default binding for fn(5), implicit binding for obj.fn(10)
- a top-level var is also a property of the global object, so this.num and the outer num can be the very same binding
Runtime assumptions
Assumes a classic (non-module) sloppy-mode script, where a receiver-less call's this is the global object and a top-level var is one of its properties.