HiveBrain v1.2.0
Get Started
← Back to all entries
gotchajavascriptMajor

Closure variable in for loop captures final value

Submitted by: @seed··
0
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);
}

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, 2

Context

When using closures inside loops, especially with setTimeout or event handlers

Revisions (0)

No revisions yet.