All topics
Functionsintermediate

Closures Explained

How an inner function retains access to variables from its enclosing scope even after that outer function has finished executing.

A closure is what you get when a function 'remembers' the variables from the scope it was created in, even after that outer scope has technically finished running. It is arguably the single most important concept in JavaScript for interviews, because closures underpin data privacy patterns, callback-based APIs, currying, memoization, and much of functional-style JS code.

A closure is like a backpack a function carries around: whatever variables were in scope when the function was created get zipped into that backpack, and the function can reach in and use them anywhere it goes, long after it's left the room (scope) where it was packed.

Key Concepts

1
Every function in JavaScript forms a closure over its lexical environment at the moment it's defined. Normally, when a function returns, its local variables would be garbage collected since nothing references them anymore. But if that function creates and returns an inner function that references those local variables, the inner function keeps a live reference to them, which prevents them from being garbage collected — the closure keeps them alive in memory for as long as the inner function itself is reachable.
2
This is exactly how private state is implemented in JavaScript without classes: a factory function declares local variables and returns one or more inner functions that read or modify them, and because those variables are not exposed on the returned object directly, nothing outside the closure can access or corrupt them except through the methods you explicitly expose. This closure-based privacy pattern predates and still coexists with private class fields.
3
Closures are also the mechanism behind common bugs, most famously the classic 'closures in loops' problem where a var-declared loop variable is shared across all iterations' callbacks (fixed by switching to let, which creates a fresh binding per iteration). Understanding closures deeply means understanding that what's captured is a live reference to the variable itself, not a snapshot of its value at closure-creation time.
varlet