What is going on here
This is the most-asked JavaScript interview question that is really two questions wearing one coat: a closure question and an event loop question. The closure half is why every callback sees the same i. The event loop half is why every callback runs after the loop has already finished.
var creates one binding for the whole enclosing function. All three arrow functions close over that single binding — not over a copy of its value. Meanwhile setTimeout(fn, 0) does not run fn now; it hands fn to the browser, which queues it as a task. Tasks only run once the call stack is empty, and the stack is not empty until the entire script — loop included — has finished. By then i has been incremented to 3.
Swapping var for let fixes it, and not because let is "safer": a let declaration in a for statement gets a fresh binding per iteration, copied forward each pass. Each callback then closes over its own i, so you get 0, 1, 2. The old pre-let fix was an IIFE that took i as an argument, creating the same per-iteration scope by hand.
Common questions
Why does setTimeout in a for loop print the last value?
Because a var-declared loop variable is a single binding shared by every callback, and none of those callbacks run until the loop and the rest of the script have finished. By the time the first one executes, the shared variable already holds its final value.
How do I make setTimeout in a loop print 0, 1, 2?
Declare the counter with let instead of var. In a for statement, let creates a new binding on every iteration, so each callback closes over its own copy. Passing the value as an argument — setTimeout(fn, 0, i) — or wrapping the body in an IIFE achieves the same thing.
Does setTimeout with 0 milliseconds run immediately?
No. Zero is a minimum delay, not a schedule. The callback becomes a task, and a task can only run once the call stack is empty and the microtask queue has drained.
Every question on one page →·Run your own code →
Embed this figure in your own post →Embed this figure
Drop this into any article or course page. It stays interactive — readers can step through it without leaving your site.