What a closure actually is
Function + its lexical environment.
- A closure = function bundled with the lexical environment where it was defined.
- Every function in JS forms a closure — the term matters most when the inner function outlives its parent.
- The parent’s Execution Context is destroyed, but closed-over variables live on through the closure’s reference.
- Closures carry the entire scope chain — inner function can see outer, grandparent, …, all the way to global.
Reference, not copy
Closures track the live variable.
- Closures do not snapshot values — they hold a reference to the variable’s memory.
- Changes to the variable after the closure is created are visible when the closure runs.
- This is exactly why
var+ setTimeout loop prints the finali, not the iteration value. - Same for
letreassignment:let name = "A"; … name = "B"; return display;→ closure sees"B".
The setTimeout loop classic
Why `var` prints 6, 6, 6, 6, 6.
for (var i=1; i<=5; i++) setTimeout(…, i*1000)→ one sharedi(function scope). All callbacks see finali = 6.- Fix 1: swap
var→let. Each iteration creates a fresh block-scopedi; each closure gets its own. - Fix 2: wrap in a helper
function close(j) { setTimeout(…, j*1000) } close(i)—jis a new local per call. - Fix 3: IIFE
(function(j){ setTimeout(…, j*1000); })(i)— same idea, inline.
Data hiding & factories
The productive use of closures.
- Private state:
function counter(){ var count=0; return ()=>{ count++; return count; } }—countis unreachable from outside. - Each call to the factory returns an independent closure →
counter1andcounter2do not share state. - Currying:
multiply(2)(5) === 10— the outer arg is closed over by the inner function. - Memoization: a cache
const cache = {}trapped in the closure persists across every call to the returned function.
Closure + Garbage Collection
The only real downside.
- A closed-over variable cannot be GC’d while the closure is alive → memory leak risk.
- Classic pitfall: event listeners that close over large objects and never get removed.
- V8 is smart: only variables actually referenced by the closure are retained. Unused siblings can be collected.
- Hygiene: remove listeners when done, clear intervals, null out closure references when you’re finished with them.
Everywhere in modern JS
Where you already use closures.
setTimeout/setIntervalcallbacks — they close over their arguments and outer variables.- Event handlers — every
button.addEventListener(…)callback is a closure. - React hooks —
useStatereturns setter functions that close over internal state. - Iterators, generators, partial application, module pattern — all powered by closures.
Comments
Comments are disabled in this environment. Set
PUBLIC_GISCUS_REPO,PUBLIC_GISCUS_REPO_ID, andPUBLIC_GISCUS_CATEGORY_IDto enable.