Closures & Scope Chain — How Functions Remember Outer Variables
The internal structure of scope chains created by Lexical Environment objects
function makeCounter() {
let count = 0;
return function() { return ++count; };
}
const counter = makeCounter();
counter(); // 1
counter(); // 2 — count is still alive
makeCounter() already returned, but the inner function still uses count. This is a closure.
V8 Internals — Lexical Environment
Every function execution creates a Lexical Environment object storing local variables and an outer reference.
The anonymous function's [[Environment]] internal slot references makeCounter's Lexical Environment. As long as this reference exists, count won't be GC'd.
On counter() call: look for count in own Lexical Environment → not found → follow outer → find count in makeCounter's environment. This is the scope chain.
Memory Leak Warning
Closures referencing outer variables prevent that environment from being GC'd. Event listeners with closures that aren't removed cause memory leaks.
Key Points
On function creation, current Lexical Environment saved in [[Environment]] slot
Variable lookup follows scope chain: own env → outer → outer...
If a function referencing outer variables is alive, that Lexical Environment won't be GC'd
Closures in event listeners must be released with removeEventListener