Why Does setTimeout Print 3 Three Times? Explained
Why does setTimeout print 3 three times? Because var is function-scoped, so all three callbacks close over the same i — and closures capture variables, not values. The one-word fix is let; the real lesson is how closures actually work, with real-world examples.
Why does setTimeout print 3 three times? Because var is function-scoped: all three setTimeout callbacks close over the *same* i , and by the time any callback runs, the loop has finished and i is 3. Change var to let and each iteration gets its own i , printing 0, 1, 2. That's the interview answer you memorized — and it's incomplete. It tells you *what* to type, not *why* it works. The real lesson: closures capture variables, not values. Every callback holds a live reference to the variable i , so each one sees whatever i has become when it finally executes. Understand that sentence and you understand closures; the var → let fix is just one application of it. Minimal working example: the 6-line repro Save as loop.js and run with node loop.js (Node 22 LTS): for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // Output: 3, 3, 3 for (let j = 0; j < 3; j++) { setTimeout(() => console.log(j), 0); } // Output: 0, 1, 2 Two mechanisms combine to produce the surprise. First, setTimeout(fn, 0) does not run the callback immediately — it schedules it to run after the current synchronous code finishes, so the entire loop completes before any callback fires. Second, var is function-scoped, meaning there is exactly one i shared across all three iterations; each callback captured that same variable and reads it after the loop, when it holds 3. With let , the for loop creates a fresh binding of j per iteration, so each callback captures its own variable holding its own value. Gotchas: why does setTimeout print 3 three times — and its cousins setTimeout(fn, 0) waits for the call stack to clear. The delay is a *minimum*, not a guarantee. If the main thread is busy, the callback waits. This is why the loop always finishes first — and it's the same reason a…