Question 12 / 14
Why do all three setTimeout callbacks log 3, not 0, 1, 2?
Topic: Closures
var creates one shared binding for the whole loop, so every callback closes over the same final value.
Solve it with the execution visualizerStep through every binding, function call, and console output below.Predict the output
Predict the output. Does each loop iteration give its callback a private i, or do all three share one?
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 100);
}Reveal the answer and explanation
Expected output
3
3
3Why this happens
var i is declared once for the entire loop, not once per iteration, so all three callbacks passed to setTimeout close over that exact same i binding.
The loop runs to completion synchronously, incrementing the shared i to 3 and registering all three callbacks in the timer task queue before any of them can run.
Once the synchronous code finishes, the queued callbacks run one by one. Each looks up i in the shared outer scope and finds the same final value, 3.
What this question tests
- var is function-scoped, not block-scoped
- closures capture bindings, not snapshots of values
- queued callbacks run only after synchronous code finishes
Runtime assumptions
The visualizer treats setTimeout as a macrotask that always runs after the current synchronous code completes, matching Node.js, browsers, and other standard JavaScript runtimes. Replacing var with let would give each iteration its own binding and print 0, 1, 2 instead.