Chapter IX · Scope

Lexical Environment

A lexical environment is the internal record the JavaScript engine actually uses to implement scope — a map of variable names to their current values, plus a link to the outer environment that contains it.

01 How It Works

Think of a lexical environment as an index card: one side lists the local variables and their values, and the other side has an arrow pointing to the next card out — following that trail of arrows from any card eventually reaches the global card.

Every scope you've read about so far — global, function, block — is a mental-model description of something the engine implements as a lexical environment. Each one has two parts: an environment record (the actual name → value bindings) and a reference to the outer lexical environment. The scope chain from the previous article is really just this chain of environment-record references, followed one link at a time. When a function is created, it stores a reference to the lexical environment active at that moment — that's the mechanism closures use to keep variables alive even after the function that created them has returned.

example.js
function createEnv() {
  let x = 10;
  return () => x; // the returned function keeps a live link to createEnv's environment
}
const getX = createEnv();
console.log(getX()); // 10
  1. 1. Whenever a scope is entered (a function call, a block), the engine creates a new lexical environment.

  2. 2. Its environment record is populated with that scope's declared variables and parameters.

  3. 3. It stores a reference to the outer lexical environment — the same reference every function created in this scope will use to resolve outer variables, even later, even after this scope has otherwise finished running.

02 Practical Example

Here is how you might see this concept applied in real-world code:

practical.js
function outer() {
  let counter = 0;
  function increment() {
    counter++; // reads and writes through the link to outer's lexical environment
    return counter;
  }
  return increment;
}

const inc = outer();
console.log(inc()); // 1
console.log(inc()); // 2 — outer()'s lexical environment is still alive,
                     // kept around by inc()'s reference to it

Key Takeaway

"Scope" is the concept; "lexical environment" is the engine's actual mechanism for it — an environment record plus an outer-environment link — and that link is precisely what keeps a closure's captured variables alive.

Related Concepts