Navigate
Search topics, hooks, and fundamentals
The classic interview question: why do all your loop callbacks print the same value? Understanding this unlocks how closures really work.
With var, all iterations share the same variable. By the time the callbacks execute, the loop is finished and i is already at its final value:
// THE TRAP — var is function-scoped
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // all print 3!
}, 100);
}
// There's only ONE 'i', and it's 3 by the time callbacks runWatch the difference between var and let in real time. Each button schedules 3 timeouts — but the results are very different:
let is block-scoped: each loop iteration creates a new binding. Each closure captures its own unique copy:
// THE FIX — let is block-scoped
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // prints 0, 1, 2 ✅
}, 100);
}
// Each iteration creates its own 'i' — a new capsule each timeBefore let existed, developers used an Immediately Invoked Function Expression (IIFE) to create a fresh scope per iteration:
// Pre-ES6 fix: IIFE creates a new scope per iteration
for (var i = 0; i < 3; i++) {
(function (captured) {
setTimeout(() => {
console.log(captured); // prints 0, 1, 2 ✅
}, 100);
})(i);
}var is function-scoped — one variable shared across all iterationslet is block-scoped — each iteration gets its own binding (its own time capsule)var creates a trap