Closures Theory
A closure is a function bundled with references to its lexical environment, allowing inner functions to keep using outer scope bindings even after the outer function returns.
What it is
When a function is defined, JavaScript stores a link to the scope where that function was created. That scope link is lexical and does not depend on how the function is later called.
If the function outlives the scope where it was declared, JavaScript preserves the needed bindings so the function can still access them. This preserved access is closure behavior.
Closures are fundamental for private state, function factories, memoization, and module patterns where internal details should not be exposed globally.
Interview framing: define Closures in one sentence, then explain one concrete runtime behavior and one common pitfall with a short code example.
How it works
- Step 1: an outer function creates local bindings and returns an inner function.
- Step 2: the inner function keeps a reference to the outer lexical environment.
- Step 3: later calls to the inner function read or update those captured bindings.
- Step 4: the captured environment is eligible for garbage collection only when nothing references the closure anymore.
Common mistakes
Assuming closures capture values, not bindings
Closures generally retain references to bindings, so later changes to a captured variable are visible to the closure.
Fix: Treat captured variables as shared state and create new bindings when isolation is required.
Accidentally retaining large objects
Closures can keep data alive longer than expected, which may increase memory usage if long-lived handlers capture heavy objects.
Fix: Capture only needed data and detach listeners or clear references when components unmount.
Using var in loops with async callbacks
var has function scope, so callbacks may all read the same final loop value instead of per-iteration values.
Fix: Use let for block-scoped loop variables or create a per-iteration factory function.
Interview questions
Common interview prompts with concise model answers.
When is a closure created?
A closure is formed when a function is created, because the function stores a reference to its lexical environment at definition time.
function makeCounter() {
let count = 0;
return () => ++count;
}
const next = makeCounter();
next(); // 1
next(); // 2Do closures cause memory leaks by default?
No. They are normal language behavior. Problems happen when long-lived closures keep unnecessary references alive.
Can closures implement private state?
Yes. Returning functions that access internal variables is a common way to expose behavior while keeping state inaccessible from outside.
How do closures interact with async code?
Async callbacks still use lexical scoping, so they read the captured bindings that exist when they eventually execute.
Related concepts
Continue with these concepts to strengthen your mental model.