Q1 — basic closure capture
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
1
2
3
1inner closes over count by reference, not by value. Each call to fn() reads and increments the same count variable in outer’s scope. fn2 is a fresh invocation of outer, creating an independent count starting at 0.
Q2 — classic var loop bug
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
3
3
3All three functions close over the same i variable (because var is function-scoped, not block-scoped). By the time any function is called, the loop has finished and i === 3.
Q3 — IIFE fix for the loop bug
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
0
1
2The IIFE immediately invokes a new function with i passed as the argument j. Each iteration creates a new scope with its own j, freezing the current value of i. The inner function closes over j, which is independent per iteration.
Q4 — closure over a variable that changes
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
10
20Closures capture variables by reference, not snapshot. getX always reads the current value of x. When x changes to 20, the next call sees 20. This is why stale closures in React happen — a hook’s closure captures the value at the time the function was created, but if the variable changes and the function isn’t recreated, it sees the old value.
Q5 — multiple closures sharing a variable
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
2All three methods close over the same count — they share the binding. increment is called 3× (count = 3), decrement once (count = 2).
Q6 — function factory with parameter
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
10
15
12double closes over factor = 2; triple over factor = 3. They’re independent closures with different factor values. triple(2) = 6, then double(6) = 12.
Q7 — stale closure in setTimeout
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
42The callback closes over val by reference. By the time the setTimeout fires (100ms later), val has been updated to 42. It reads the current value at execution time, not a snapshot from when setTimeout was called.
Q8 — closure inside object method
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
undefinedThe inner function is a plain function, not a method. When called as fn() (not obj.something()), this is the global object (window in browser) or undefined in strict mode. window.value is undefined. Fix with () => (arrow inherits outer this) or .bind(obj).
Q9 — IIFE output
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
7
42
"undefined"IIFEs execute immediately and return their value. result is 7. The second IIFE logs 42 internally. secret is scoped inside the IIFE — it doesn’t pollute the outer scope, so typeof secret is "undefined" (no ReferenceError because typeof on an undeclared name is safe).
Q10 — closure counter with reset
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
6
7
7
5start and count are both in the closure. reset() sets count back to start (the original argument), which is still accessible because it’s part of the outer function scope.
Q11 — closure over let in switch
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
Error: Identifier 'msg' has already been declaredAll case clauses in a switch share one block scope. The two let msg declarations conflict — you get a SyntaxError at parse time. Fix: wrap each case body in {} to give each case its own block.
case 1: { let msg = 'one'; ... break; }
case 2: { let msg = 'two'; ... break; }Q12 — closure in class method
console.log. Async logs (setTimeout/Promise) appear in real execution order.Answer & why
NaN (after each tick)The function() callback loses this — inside a regular function passed to setInterval, this is window/undefined. window.seconds is undefined, and undefined++ is NaN. Fix: use an arrow function () => { this.seconds++; } — arrows inherit this from the enclosing class method.
var loop bug and stale closures in React hooks. When you need to freeze a value, either use let (fresh binding per iteration), an IIFE (new scope with value passed as argument), or copy the value into a new variable.