Closures & Scopecritical

Closure

A closure is a function that retains access to variables from its lexical scope even after that outer function has returned. The inner function 'closes over' those variables.

Memory anchor

A closure is a backpack that a function carries everywhere — inside the backpack are all the variables from where it was born, even if that birthplace no longer exists.

Expected depth

Closures are created every time a function is defined inside another function. They enable private state, factory functions, and the module pattern. The classic bug: using var in a loop and capturing the loop variable in a callback — all callbacks share the same variable binding (not value), so they all see the final value. Fix: use let (block scope) or IIFE to create a new scope per iteration.

Deep — senior internals

Under the hood, closures are implemented via the Environment Record in the spec and as HeapClosure objects in V8. Variables captured by a closure are 'promoted' to the heap (a context object) rather than living on the stack. V8's escape analysis determines which variables need heap promotion. This is why closures have a memory cost: the entire lexical environment chain is kept alive as long as any inner function references it. For large data, this can cause unintended memory retention — the fix is to explicitly nullify references or restructure so the closure captures only what it needs.

🎤Interview-ready answer

A closure is a function bundled with its lexical environment — the variables in scope when the function was defined. They enable private state and encapsulation without classes. The key insight is that closures capture variable bindings (references), not values, which causes the classic loop-with-var bug where all async callbacks see the loop variable's final value.

Common trap

Closures in loops with var are perhaps the most common JavaScript interview trap. var is function-scoped, so all iterations share one binding. Using let creates a new binding per iteration. The IIFE fix works but is outdated — in modern code, always prefer let/const in loops.