Question 12 / 14

Why do all three setTimeout callbacks log 3, not 0, 1, 2?

Topic: Closures

var creates one shared binding for the whole loop, so every callback closes over the same final value.

Solve it with the execution visualizerStep through every binding, function call, and console output below.

Predict the output

Predict the output. Does each loop iteration give its callback a private i, or do all three share one?

for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 100);
}
Reveal the answer and explanation

Expected output

3
3
3

Why this happens

var i is declared once for the entire loop, not once per iteration, so all three callbacks passed to setTimeout close over that exact same i binding.

The loop runs to completion synchronously, incrementing the shared i to 3 and registering all three callbacks in the timer task queue before any of them can run.

Once the synchronous code finishes, the queued callbacks run one by one. Each looks up i in the shared outer scope and finds the same final value, 3.

What this question tests

  • var is function-scoped, not block-scoped
  • closures capture bindings, not snapshots of values
  • queued callbacks run only after synchronous code finishes

Runtime assumptions

The visualizer treats setTimeout as a macrotask that always runs after the current synchronous code completes, matching Node.js, browsers, and other standard JavaScript runtimes. Replacing var with let would give each iteration its own binding and print 0, 1, 2 instead.

Specification references

JavaScript Code EditorDirectly edit or paste custom code
Step 0 of 0
StepSpaceRun
Press → (Step) or Space (Run)
Phase 1: Compilation(Hoisting & Memory Setup)
Phase 2: Execution(Line-by-line Evaluation)
Execution Step Breakdown

Press "→" / click "▶" to step line-by-line, or press "Space" / click "▶ Run" for auto-play.

Scope Chain
Lexical Environment Chain: Inner Scope → Outer [[Scope]] → Global (GO)
No active scope chain
CALL STACKStack of Execution Contexts (LIFO)
LIFO Stack Frames
Global Execution Context (GEC)
▶ Active Frame
HEAP & MEMORY SPACEAllocated Objects (GO, AO, FunctionObjects, ER)
ECMAScript Heap Area
No objects in memory
Console Output
console.log(...) Stream
No output generated yet