Closures & Scopeeasy

Explain closures — and the classic loop bug

What is a closure? Demonstrate the classic `var` loop bug and fix it using a closure, `let`, or IIFE.

Asked at Google, Meta, Amazon, Airbnb

#closures#var#let#scope

Answer

// Usage
// A closure is a function that retains access to its outer
// (enclosing) scope even after the outer function has returned.

function makeCounter() {
  let count = 0              // captured by the returned function
  return () => ++count       // this is the closure
}
const counter = makeCounter()
counter() // 1
counter() // 2

// ─────────────────────────────────────────────────────────
// Classic loop bug with var
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100)
}
// Prints: 3, 3, 3  — all share the same 'i' variable

// Fix 1: use let (block-scoped, new binding per iteration)
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100)
}
// Prints: 0, 1, 2

// Fix 2: IIFE to capture each value
for (var i = 0; i < 3; i++) {
  (function(j) {
    setTimeout(() => console.log(j), 100)
  })(i)
}

Practise more Closures & Scope questions →