Hiprup

What is the difference between var, let, and const in loops?

The choice of declaration changes loop behaviour, especially with closures.

  • var — one shared, function-scoped variable; async callbacks all see the final value.

  • let — a fresh binding per iteration, so each callback captures its own value.

  • const — works in for...of/for...in (new binding each time), but not in a classic counting for loop you reassign.

This is why a let loop fixes the classic setTimeout-in-a-loop bug.

// var — one shared variable (BUG with async)
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 10);
}
// Output: 3, 3, 3 (all see final i)

// let — new variable per iteration (CORRECT)
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 10);
}
// Output: 0, 1, 2 (each captures its own i)

// const in for...of (new binding per iteration)
const arr = ['a', 'b', 'c'];
for (const item of arr) {
  setTimeout(() => console.log(item), 10);
}
// Output: 'a', 'b', 'c' (each captures its own item)

// const in regular for — ERROR
// for (const i = 0; i < 3; i++) {} // TypeError: Assignment to constant

var i: one variable — all setTimeout callbacks reference the same i (3 after loop ends). let i: new variable per iteration — each callback captures its own copy. const works in for...of (new binding per iteration, no reassignment needed) but fails in regular for (i++ reassigns, violating const).

This is THE most asked JS gotcha. var = shared (bug), let = per-iteration (correct), const = per-iteration in for...of only. Walk through step-by-step: var creates ONE i, all callbacks close over it, by the time they run i=3. let creates THREE separate i variables.

What is the difference between var, let, and const in loops? | Hiprup