The Scope Chain & Lexical Environment
Quick Overview
A variable resolves by where the function was written, never where it was called. The lookup walks outward through each enclosing scope and throws `ReferenceError` only on reaching global empty-handed.
Deep Dive
1. Where Can Variables Be Found?
Scope determines where variables are accessible in your code. Lexical Environment refers to where code is physically written in your script hierarchy.
2. Why It Matters
When a function accesses a variable, JavaScript searches its local scope first. If not found, it travels UP the Scope Chain to parent scopes until it reaches the Global Scope.
3. The Scope Chain Search Diagram
Outer scopes cannot look inside inner function scopes, but inner functions have full access to their parent lexical environments:
[ Global Scope ] -> globalVar = "Global"
^
| (Searches Upward)
[ Outer Function ] -> outerVar = "Outer Scope"
^
| (Searches Upward)
[ Inner Function ] -> localVar = "Local"
const globalName = "DevLoom";
function outer() {
const outerVar = "Outer Scope";
function inner() {
// Searches local -> Outer -> Global
console.log(`${globalName} | ${outerVar}`);
}
inner();
}
outer(); // Output: "DevLoom | Outer Scope"
4. Lexical Scope vs. Dynamic Scope
JavaScript uses Lexical Scoping (Static Scoping). This means variable resolution depends on where functions are defined in the source code, NOT where they are called from!
5. Common Mistakes
- Polluting Global Scope: Assigning a variable without
const,let, orvarinside a function (e.g.score = 100) implicitly attaches it to the globalwindowobject in non-strict mode. - Assuming Parent Can Read Child Variables: Parent scopes CANNOT read variables declared inside child functions!
6. Try It Yourself
Write it yourself. The tests below run against your code.
Fix Lexical Scope Lookup
Examples
7. Next Steps
Keep variables tightly scoped inside functions. Next, let's explore Block Scope and the Temporal Dead Zone (TDZ)!
Next Up in JavaScript Engine & Core Language
Data Types in JavaScript: Primitives vs. Objects
Primitives copy by value and objects copy by reference, so `b = a` duplicates a number but shares an object. That single distinction explains most surprise mutations in a codebase.
Variables: const, let & var (The Box Metaphor)
`const` prevents reassignment, not mutation: a `const` object's properties can still be changed. `let` is scoped to its block, while `var` is function-scoped and leaks out of loops.
Strings & Template Literals `${}`
Only backticks interpolate: `${user}` reads the variable, while the identical text in quotes prints literally. Strings are immutable, so every method returns a new one rather than editing in place.