Typorithm · medium

Closures in Loops

closure-in-loopsinterview-questionsclosuresloopslet-binding
Saved on this device
Full lesson · 8 learning steps Open any exercise for focused practice
1

Step 1 of 8 · intro card

Learn Closures in Loops

0%

Closures & Scope

for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)) logs 3, 3, 3 because every callback closes over the same shared i, which equals 3 by the time they run. Fixing it with let gives each iteration its own binding (0, 1, 2), and an IIFE that captures the current value works too.

The classic bug: a var loop shares one i across all iterations, so each setTimeout callback closes over the same variable. By the time the callbacks fire the loop is done and i is 3, so they all log 3, 3, 3.

Swapping var for let fixes it: let creates a fresh, per-iteration binding of j, so each closure captures its own copy and the callbacks log 0, 1, 2.

Before let, the idiomatic fix was an IIFE — wrapping the body in (function (k) { ... })(i) — which copies the current value into a new parameter, giving each closure its own captured value.

01

var loops share one variable across all iterations.

02

Callbacks log the final value (3, 3, 3) because they run later.

03

let gives a per-iteration binding (0, 1, 2); an IIFE also works.

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i)) // logs 3, 3, 3 — same i
}
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j)) // logs 0, 1, 2 — fresh binding
}

Read the implementation

Connect each part of the code to the concept before you type.

1. Shared var counter

A single var i is shared across every iteration, so all closures created in the loop point at the same variable.

for (var i = 0; i < 3; i++) {

2. The classic bug

Each callback runs after the loop finishes and reads the one shared i, which is now 3, so it logs 3, 3, 3.

setTimeout(() => console.log(i)) // logs 3, 3, 3 — same i

3. Per-iteration binding

let creates a brand-new j for each iteration, so each closure captures its own copy.

for (let j = 0; j < 3; j++) {

4. The fix

Because each j is a separate binding, the callbacks log 0, 1, 2 as expected.

setTimeout(() => console.log(j)) // logs 0, 1, 2 — fresh binding

A complete learning loop

01

Understand

Read the concept map and follow the code breakdown.

02

Reconstruct

Type the implementation, repair mistakes and work through every recall exercise.

03

Verify

Use the final check without hints; revisit weak concepts in short practice sessions.

Closures in Loops: Lesson & Practice · Typorithm | ApplyDjinn