Before beginning with lexical environment . you have to knowledge about how execution context works and how scope works in javascript .you can read from here
let's start with the what is meaning of lexical
Lexical: The term "lexical" refers to the way in which programming languages determine the scope of variables and functions based on their location or position in the source code.
Lexical Environment
A lexical environment is the set of variables and functions that are in scope at any given point in the code. Every time the when JavaScript engine creates an execution context to execute the function or global code, it also creates a new lexical environment to store the variables defined in that function during the execution of that function. It is created by the combination of the following two things:
The current scope's environment
A reference to the outer scope's environment (also known as the scope chain)
scope refers to the visibility or accessibility of variables, functions, and objects in a particular part of the code.ach block of code creates scope and a lexical environment.
javascript looks at a lexical environment when you ask for a variable while running a line of code inside any particular execution context if it can’t find that variable in its block scope it will go at the outer reference or block and look for the variables And that outer reference is where the function sits lexically is its outer environment.
sometimes when the same variable or a new copy like is called the same function twice then each gets its execution context and though it looks like the same variable, but actually it is two different variables in memory.
Lexical Environment: Local Memory + Lexical Environment of its Parent
So in short, a lexical environment is a place where variables and functions live or physically present during the program execution.
For example:
function two(){
var a;
console.log(a);
}
function one(){
var a=2;
console.log(a);
two();
}
var a=1;
console.log(a);
one();
//output
//1 2 undefined
When the program runs, the global execution context is created first, and a
is assigned a value of 1
in the global scope.
Next, the one()
function is called. When one()
is called, a function execution context is created for one()
. In the function execution context of one()
, a new variable a
is created and assigned the value of 2
.
After that, one()
calls the two()
function. A new function execution context is created for two()
. In the execution context of two()
, a new variable a
is created but is not assigned any value yet.
When console.log(a)
is called inside the two()
function, JavaScript first looks for the value of a
inside the function's own execution context. Since a
has not been assigned a value yet in the execution context of two()
, undefined
is printed to the console.
Finally, control returns to the execution context of one()
, and the function completes. After that, control returns to the global execution context and the program terminates.
In terms of lexical environment and scope, each function creates its own execution context with its own lexical environment. The lexical environment of a function consists of all the variables that are in scope at the time the function is defined. In this case, the two()
function has access to its own variables, as well as the variables in the execution context of one()
and the global execution context. However, one()
and the global execution context do not have access to the variables inside two()
since they are not defined in their lexical environments.
Let's take another example:
function two(){
console.log(a);
}
function one(){
var a=2;
console.log(a);
two();
}
var a=1;
console.log(a);
one();
//output
//1 2 1
When the program runs, the global execution context is created first
The global variable
a
is declared and assigned a value of1
in the global scope.When
one()
is called, a function execution context is created forone()
. Inside theone()
function, a new local variablea
is declared and assigned a value of2
in its own scope. This local variablea
shadows the global variablea
within the scope of theone()
function.Inside the
one()
function,console.log(a)
is called, which outputs the value of the local variablea
, which is2
.The
one()
function then calls thetwo()
function. A new function execution context is created fortwo().
Inside thetwo()
function, the code attempts to access the variablea
. Since there is no local variablea
declared within thetwo()
function, it looks up the scope chain to find the variablea
in the parent scope, which is the global scope. Therefore, it outputs the value of the global variablea
, which is1
.Finally, control returns to the global scope, and
console.log(a)
is called again. It outputs the value of the global variablea
, which is1
.
Lexical Scope
let's understand lexical scope and scope chain with some other examples
function a() {
let a = "a";
function b() {
let b = "b";
function c() {
let c = "c";
console.log(b);
}
c();
}
b();
}
a()
lexical scope refers to the ability of a function scope to access variables from the parent scope. When there is lexical scope, the innermost, inner and outermost functions may access all variables from their parent scopes all the way up to the global scope.
When the program runs, the global execution context is created first. but here when no global variable is declared thus the default window object, this and function declaration are assigned only
The when
a()
function is called. a function execution context is created on the top of global execution context .Inside thea()
function, a local variablea
is declared and assigned the value"a"
.The
b()
function is defined inside thea()
function. then another a function execution context is created on the top ofa()
function execution context . Inside theb()
function, a local variableb
is declared and assigned the value"b"
.The
c()
function is defined inside theb()
function. then another a function execution context is created on the top ofb()
function execution context . Inside theb()
function, Inside thec()
function, a local variablec
is declared and assigned the value"c"
.Inside the
c()
function,console.log(b)
is called. JavaScript first looks for the variableb
within the local scope of thec()
function. Since there is no variableb
declared within thec()
function, it looks up to parent scope. which is theb()
function. where inb()
we found the variableb
value . this is due to ability of a function scope to access variables from the parent scope is lexical scope.
let's take another example with some modification
let d="global";
function a() {
let a = "a";
function b() {
let b = "b";
function c() {
let c = "c";
console.log(d);
}
c();
}
b();
}
a()
The scope chain is the mechanism by which JavaScript determines which variables are accessible in a particular portion of the code. When a variable is accessed in a particular portion of the code, JavaScript looks for the variable in the current scope. If the variable is not found in the current scope, JavaScript looks for the variable in the outer scope, and this process continues until the variable is found or the global scope is reached.
When the program runs, the global execution context is created first. but here variable
d
is declared in the global scope and assigned the value"global"
.thus the default window object, this and function declaration are assigned .The when
a()
function is called. a function execution context is created on the top of global execution context.Inside thea()
function, a local variablea
is declared and assigned the value"a"
.The
b()
function is defined inside thea()
function. then another a function execution context is created on the top ofa()
function execution context . Inside theb()
function, a local variableb
is declared and assigned the value"b"
.The
c()
function is defined inside theb()
function. then another a function execution context is created on the top ofb()
function execution context . Inside theb()
function, Inside thec()
function, a local variablec
is declared and assigned the value"c"
.Inside the
c()
function,console.log(d)
is called. JavaScript first looks for the variabled
within the local scope of thec()
function. Since there is no variabled
declared within thec()
function, it looks up to parent scope which is theb()
function. where inb()
we not found the variable value ofb
. first looks at the lexical scope . if we do not find in lexical environment then it looks up the scope chain to find the variabled
in the parent scope, which is theb()
function. . Ifd
is not found in theb()
function, it looks up the scope chain again to find the variabled
in the parent scope, which is thea()
function. Ifd
is still not found, it continues to look up the scope chain until it reaches the global scope. In this case, the variabled
is found in the global scope, and its value is"global"
. Therefore, it outputs"global"
.