Skip to content
Optimal Lab

Frontend · interactive

Closures

A function remembers the variables that were in scope where it was created, not copies of their values. That's a closure. It explains the classic loop bug, and it's how JavaScript does private state.

for (var i = 0; i < 3; i++) {
  setTimeout(() => log(i), 0);
}

Scopes kept alive

function scope (one for the whole loop)

i = 3

↖ callback 1↖ callback 2↖ callback 3

output: 3 3 3

var creates one i for the whole function. All three callbacks close over that same variable, and by the time they run the loop has left it at 3.

Example

Step 2 of 4

  1. 1

    Functions carry their birthplace

    When a function is created it keeps a link to the surrounding scope. Calling it later still sees those variables.

    Variables, not snapshots of values.

  2. 2

    var shares one variable

    All callbacks see the same i, which has finished at 3 by the time they run.

    Same trap with stale state in React effects.

  3. 3

    let makes one per iteration

    Block scoping gives each loop pass its own binding.

    Prefer let and const everywhere.

  4. 4

    Private state

    A closure's variables are reachable only through the functions that captured them: counters, memoisation caches, module patterns.

    Captured objects stay in memory as long as the function does.

In production

Tools and technologies

Closures are everywhere in JavaScript: callbacks, hooks, modules.

Not tied to one language — use these names when you search docs or design a system.