gotchajavascriptMajor
Closure variable in for loop captures final value
Viewed 0 times
closure loopvar vs letloop variablesetTimeout loopblock scope
Problem
Using var in a for loop and referencing the variable in a closure (setTimeout, event handler) captures the same variable — all closures see the final value. Classic interview question.
Solution
Use let instead of var — it creates a new binding per iteration:
// BAD: var — all closures share one variable
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // prints 3, 3, 3
}
// GOOD: let — each iteration gets its own i
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // prints 0, 1, 2
}
// ALT: IIFE (pre-ES6 solution)
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
// BAD: var — all closures share one variable
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // prints 3, 3, 3
}
// GOOD: let — each iteration gets its own i
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // prints 0, 1, 2
}
// ALT: IIFE (pre-ES6 solution)
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
Why
var is function-scoped, not block-scoped. The for loop has one 'i' variable that all closures reference. By the time the closures execute, the loop has finished and i equals 3. let is block-scoped — each iteration creates a new variable.
Gotchas
- This only matters when closures outlive the loop iteration (async, callbacks)
- const in for...of loops also creates a new binding per iteration
- forEach naturally avoids this because its callback gets the value as a parameter
Code Snippets
Closure in loop fix
// The classic gotcha
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 10);
}
// Output: 3, 3, 3
// The fix: use let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 10);
}
// Output: 0, 1, 2Context
When using closures inside loops, especially with setTimeout or event handlers
Revisions (0)
No revisions yet.