JavaScript var Loop Closure: Two Explanations Quiz
The classic var-in-a-for-loop closure trap, explained two ways (shared `i` binding and the IIFE capture fix), plus two companions on the `let` per-iteration binding and a queueMicrotask version of the trap.
354 views
11
Predict the console output and explain WHY: var declared in the loop header creates a single binding that every closure shares. Walk through what i holds at the moment arr[2]() actually runs.
Examples
Example 1:
Input: see code below
Output: 5
Explanation: All five closures captured the same `i`; the loop has exited and i is 5.const arr = [];
for (var i = 0; i < 5; i++) {
arr[i] = function () {
console.log(i);
};
}
arr[2]();
// what is logged, and why?Fix the snippet using an IIFE to capture the current value of i per iteration. Keep var (do not convert to let). Verify that arr[2]() now logs 2.
Examples
Example 1:
Input: var loop wrapped with an IIFE binding x = i
Output: arr[2]() logs 2
Explanation: Each IIFE call creates a new local `x` that the inner function closes over.const arr = [];
for (var i = 0; i < 5; i++) {
// wrap an IIFE here that closes over the current i
}
arr[2](); // should log 2Replace var with let in the original snippet. Predict the output and explain WHY let fixes the bug without an IIFE. Mention what the spec calls the "per-iteration binding".
Examples
Example 1:
Input: for (let i = 0; i < 5; i++) { arr[i] = () => i; }
Output: arr[2]() returns 2
Explanation: `let` creates a fresh `i` binding each iteration, and the closure captures that iteration's binding.const arr = [];
for (let i = 0; i < 5; i++) {
arr[i] = function () {
return i;
};
}
arr[2](); // ?queueMicrotask twist: replace the array of stored functions with queueMicrotask(() => console.log(i)) inside a var loop. Predict the output, then change exactly one keyword to print 0,1,2,3,4 in order.
Examples
Example 1:
Input: for (var i = 0; i < 5; i++) queueMicrotask(() => console.log(i));
Output: 5 5 5 5 5
Explanation: The loop finishes synchronously before any microtask runs; all five microtasks read the shared `i = 5`.Example 2:
Input: change `var` to `let`
Output: 0 1 2 3 4
Explanation: Per-iteration binding gives each microtask its own `i`.for (var i = 0; i < 5; i++) {
queueMicrotask(() => console.log(i));
}
// Change exactly one keyword to get 0 1 2 3 4.