Fundamentalsbeginner
Lexical Scope and Scope Chain
How JavaScript resolves variable names based on where code is physically written, not where it is called from.
Lexical scope means that the accessibility of a variable is determined by its physical location in the source code at write time, not by which function called which at runtime. This is the mechanism that makes closures possible, and it's foundational enough that almost every JS interview touches on it in some form.
It's like a family looking up a recipe: you check your own recipe box first, and if it's not there you ask your parents, then your grandparents — the search follows your family tree (where you came from), not who happens to be visiting your kitchen today.
Key Concepts
1
When a function is defined, it captures a reference to the scope in which it was created — its lexical environment. When code inside that function references a variable, the engine first looks in the function's own local scope; if not found, it walks up to the enclosing scope where the function was *defined*, and continues up through each enclosing scope until it either finds the variable or reaches the global scope and throws a ReferenceError. This chain of nested scopes is called the scope chain.
ReferenceError
2
Crucially, this lookup is based on nesting in the source code, not on the call stack. A function defined at the top level and called from deep inside another function still only has access to the variables visible at its own definition site, plus the global scope — it does not gain access to the local variables of whatever function happens to call it. This is what separates lexical scoping from dynamic scoping (which some other languages use).
3
This model is what powers closures: an inner function retains access to its outer function's variables even after the outer function has returned, because the scope chain is fixed at definition time and kept alive as long as something still references it. Understanding scope chains also explains shadowing — when an inner scope declares a variable with the same name as an outer one, the inner declaration is found first and 'shadows' the outer variable for that scope.