Chapter 2: Illustrating Lexical Scope
In Chapter 1, we explored how scope is determined during code compilation, a model called “lexical scope.” The term “lexical” refers to the first stage of compilation (lexing/parsing). To properly reason about our programs, it’s important to have a solid conceptual foundation of how scope works. Like way back in grade school math class, getting the right answer isn’t enough if we don’t show the correct steps to get there! We need to build accurate and helpful mental models as foundation moving forward.Marbles, and Buckets, and Bubbles… Oh My!
One metaphor I’ve found effective in understanding scope is sorting colored marbles into buckets of their matching color.Imagine you come across a pile of marbles, and notice that all the marbles are colored red, blue, or green. Let’s sort all the marbles, dropping the red ones into a red bucket, green into a green bucket, and blue into a blue bucket.After sorting, when you later need a green marble, you already know the green bucket is where to go to get it.
The Marble Metaphor
- Marbles = variables in our program
- Buckets = scopes (functions and blocks)
- Colors = which scope a marble/variable belongs to
Visualizing Scope Bubbles
We’ve designated three scope colors:RED (1)
Global ScopeIdentifiers:
studentsgetStudentNamenextStudent
BLUE (2)
Function ScopeIdentifiers:
studentID(parameter)
GREEN (3)
Loop ScopeIdentifiers:
student
Scope bubbles are determined during compilation based on where the functions/blocks are written. Each scope bubble is entirely contained within its parent scope bubble—a scope is never partially in two different outer scopes.
Key Takeaways
Variables are colored by their scope
Variables are declared in specific scopes, like colored marbles from matching-color buckets.
Nested scopes inherit access
Any variable reference in a scope (or deeper nested scopes) will be labeled a marble of that same color—unless shadowed by an intervening scope.
A Conversation Among Friends
Another useful metaphor for the process of analyzing variables and scopes is to imagine conversations that occur inside the engine as code is processed and executed. Let’s meet the members of the JS engine:Engine
Responsible for start-to-finish compilation and execution of JavaScript programs
Compiler
Handles all the dirty work of parsing and code-generation
Scope Manager
Collects and maintains a lookup list of all declared identifiers, and enforces access rules
The Compilation Conversation
Let’s examine how JS processes our example program, starting withvar students = [...].
The first thing Compiler will do is perform lexing to break it down into tokens, then parse into an AST. Once Compiler gets to code generation:
Compiler asks Scope Manager
Compiler: “Hey, Scope Manager (of the global scope), I found a formal declaration for an identifier called
students, ever heard of it?”Scope Manager: “Nope, never heard of it, so I just created it for you.”Compiler continues with function
Compiler: “Hey, Scope Manager, I found a formal declaration for
getStudentName, ever heard of it?”Scope Manager: “Nope, but I just created it for you.”Compiler: “Hey, Scope Manager, getStudentName points to a function, so we need a new scope bucket.”Scope Manager: “Got it, here’s the scope bucket.”The Execution Conversation
Later, when it comes to execution of the program:
Engine: “Hey, Scope Manager (of the global scope), before we begin, can you look up the identifier getStudentName so I can assign this function to it?”
Scope Manager: “Yep, here’s the variable.”
Engine: “Hey, Scope Manager, I found a target reference for students, ever heard of it?”
Scope Manager: “Yes, it was formally declared for this scope, so here it is.”
Engine: “Thanks, I’m initializingstudentstoundefined, so it’s ready to use.”
Nested Scope
When it comes time to execute thegetStudentName() function, Engine asks for a Scope Manager instance for that function’s scope.
The function scope for getStudentName(..) is nested inside the global scope. The block scope of the for-loop is similarly nested inside that function scope.
Each scope gets its own Scope Manager instance each time that scope is executed (one or more times). Each scope automatically has all its identifiers registered at the start of the scope being executed (this is called “variable hoisting”).
How Nested Lookup Works
In thefor (let student of students) statement, students is a source reference that must be looked up. But the function scope doesn’t have a students identifier. What happens?
Engine: “Hey, Scope Manager (for the function), I have a source reference for students, ever heard of it?”
Scope Manager (Function): “Nope, never heard of it. Try the next outer scope.”
Engine: “Hey, Scope Manager (for the global scope), I have a source reference for students, ever heard of it?”
Scope Manager (Global): “Yep, it was formally declared, here it is.”
Lookup Failures
When Engine exhausts all lexically available scopes and still cannot resolve the lookup of an identifier, an error condition exists.Undefined Mess
Source Variable Not Found
Result:
ReferenceError is thrownThe error message: “XYZ is not defined”(Really means: “not declared” or “undeclared”)Target Variable Not Found
Strict Mode:
ReferenceError is thrownNon-Strict Mode: Global variable accidentally created!(This is a terrible legacy behavior)Global Auto-Creation (Non-Strict Mode)
If the variable is a target and strict-mode is not in effect:Building On Metaphors
To visualize nested scope resolution, another helpful metaphor is an office building:- The building represents our program’s nested scope collection
- The first floor is the currently executing scope
- The top level is the global scope
Continue the Conversation
By this point, you should be developing richer mental models for what scope is and how the JS engine determines and uses it from your code.Before continuing: Go find some code in one of your projects and run through these conversations. Seriously, actually speak out loud. Find a friend and practice each role with them.If either of you find yourself confused or tripped up, spend more time reviewing this material.

