Facebook Pixel

How Closures Work With Lexical Scope

Closures are a consequence of lexical scope. Here is the engine-level mechanism that makes them work.

How Closures Work With Lexical Scope

Closures are not a separate feature. They are a direct consequence of lexical scope. Understanding the mechanism makes closures click.

Lexical Scope Recap

JavaScript uses lexical (static) scope. The scope chain is determined by where functions are written in the source, not where they are called. Each function has an outer environment reference to its lexical parent's environment.

The Mechanism

  1. When a function is created, it stores a reference to its current lexical environment (the one where it was defined).
  2. When the function is called, a new execution context is created. Its outer reference is the stored environment reference.
  3. When the engine resolves a variable, it checks the local environment first, then follows the outer reference up the chain.
const globalVar = "G"; function outer() { const outerVar = "O"; function inner() { console.log(outerVar, globalVar); // O, G } return inner; } const fn = outer(); fn(); // O, G `` When `fn()` is called (after `outer` has returned), `inner`'s outer reference still points to `outer`'s environment. So `outerVar` is found. And `outer`'s outer reference points to the global, so `globalVar` is found. ### Why the Environment Survives Normally, when a function returns, its execution context is popped from the call stack and its local variables are eligible for garbage collection. But if an inner function holds a reference to the outer environment, the GC cannot free it. The environment survives. ```js function makeCounter() { let count = 0; return () => ++count; } const c = makeCounter(); // makeCounter's execution context is gone // but its lexical environment (with count) is alive because c holds a reference `` ### Each Call Creates a Separate Environment ```js function makeAdder(x) { return (y) => x + y; } const add5 = makeAdder(5); const add10 = makeAdder(10); add5(3); // 8 add10(3); // 13 `` `add5` and `add10` each have their own `x` (5 and 10), because each call to `makeAdder` created a separate lexical environment. ### The Takeaway Closures work because functions store a reference to their lexical environment at creation time. When called, the outer reference is the stored one, not the current call stack. If a function is returned or passed around, its environment reference travels with it, keeping the outer variables alive. Each call to the outer function creates a separate environment.

Closures are a consequence of lexical scope. Functions store a reference to their lexical environment at creation time. When called later, the outer reference is the stored one, so the function can access outer variables even after the outer function has returned.

Because the inner function holds a reference to the outer lexical environment. As long as the inner function exists, the garbage collector cannot free the environment. The scope chain persists.

No. Each call creates a separate lexical environment. So makeAdder(5) and makeAdder(10) each have their own x. The closures are independent and do not share state.

At creation time. The function object stores a reference to the lexical environment where it was defined. This reference does not change based on where the function is later called.

The function plus the environment. A closure is the combination of a function and its lexical environment (the variables it closes over). The function object holds a hidden reference to that environment.

Ready to master React completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.