A lexical Environment is a structure that stores variables and their relationships based on their scope. It is created every time JavaScript executes a block or function. It has two components, environment record and outer reference.
The environment record stores variables, constants, and function declarations defined in the current scope.
The outer reference is reference to the parent lexical environment. When a variable is not found in the current environment, JavaScript looks to the parent environment via the outer reference. This continues up the chain until the global lexical environment is reached or the variable is found.
Lexical Environment vs Lexical Scope
While lexical environment is the structure that stores variables and their relationships based on scope, the lexical scope is the set of rules that determines how and where these variables can be accessed. When a function is defined, it remembers the scope in which it was created. The essence of lexical scoping lies in the principle that where a variable is declared defines its scope and determines its accessibility.
Scope Chaining
The hierarchy of lexical environments forms a scope chain, which starts with the innermost function and works outward to the global scope.
Imagine you lost your wallet inside your house. You start by looking in your room (current lexical environment). If you don't find it, you check other rooms (parent environments), and finally, the entire house (global environment).
Consider the following code example
In this example, when outerFunction
is invoked, a lexical environment is created for outerFunction
. This environment contains outerVariable
and a reference to innerFunction
.
When innerFunction
is invoked, a new lexical environment is created for innerFunction
, which references the parent lexical environment (outer reference,the one for outerFunction
).
The innerFunction
has access to outerVariable
because of its lexical environment.
Let us visualise the relationship between the lexical environments using the diagram below
Global lexical environment contains the reference to outerFunction
. The outer reference is null since it is the top-level scope.
The outerFunction
lexical environment stores outerVariable
and a reference to innerFunction
. The outer reference links to the global lexical environment.
The innerFunction
lexical environment has its own scope but contains a reference to the outerFunction
lexical environment via its outer reference. This reference allows innerFunction
to access outerVariable
.
Scope Chaining in Action
When innerFunction
is invoked, a lexical environment is created for it. This environment contains its own variables (if any) and references the lexical environment of outerFunction
via the scope chain.
When the innerFunction
tries to access outerVariable
, it searches its own lexical environment. Since outerVariable
is not found in the innerFunction
's scope, JavaScript moves up the scope chain to the outerFunction
's lexical environment and retrieves the value of outerVariable
.