/ˈlɛksɪkəl ˈskoʊpɪŋ/
noun … “Scope determined by code structure, not runtime calls.”
Lexical Scoping is a scoping rule in which the visibility of variables is determined by their position within the source code. In languages with lexical scoping, a function or block can access variables defined in the scope in which it was written, regardless of where it is called at runtime. This is fundamental to closures and scope management.
Key characteristics of Lexical Scoping include:
- Static resolution: the compiler or interpreter resolves variable references based on the code's textual layout.
- Nested scopes: inner functions or blocks can access variables from outer scopes.
- Predictable behavior: variable access does not depend on the call stack or runtime sequence of calls.
- Supports closures: functions retain access to their defining environment, preserving variables after outer functions exit.
- Reduces side effects: by limiting variable visibility to specific blocks, lexical scoping minimizes accidental interference.
Workflow example: In JavaScript:
function outer(x) {
let y = x + 1
function inner(z) {
return x + y + z
}
return inner
}
fn = outer(5)
print(fn(10)) -- Output: 21Here, inner retains access to x and y from its defining scope, even though it is invoked later. The variables are resolved lexically, not dynamically based on the call context.
Conceptually, Lexical Scoping is like reading a map drawn on a table: the locations and paths are determined by the map's layout, not by the direction from which you approach it. A closure carries its portion of the map wherever it travels.