JavaScript Advanced (IV)—Execution Context
Execution context
The execution context is an abstract concept of the environment ** where the JavaScript
code is parsed ** and **execute **. Any code for JavaScript
is executed in the execution context.
type
JavaScript
has three types of execution contexts:
- Global execution context
The default execution context, or the underlying execution context. Any code that is not inside a function is in the global execution context. The global context performs two things:
- Create a global
window
object (in the browser environment). - Set the value of
this
equals the globalwindow
object.
A program will only have one global execution context.
- Function execution context
Whenever a function is executed, a new execution context is created for the function. Each function has its own execution context and is created when the function is executed. Function contexts can have as many as possible. Whenever a function execution context is created, it will perform a series of steps in the defined order.
- eval function execution context
The code executed inside the eval
function will also have its own execution context.
Create an execution context
The creation execution context is mainly divided into two stages: Creation phase and Execution phase.
Creation phase
During the creation stage, three things will be done:
- Decision of this value, i.e. This binding
- Create lexical environment components
- Create variable environment components
This binding
- Global execution context
In the global execution context, the value of this
points to the global object. (In the browser, this
refers to the Window
object).
- Function execution context
In the function execution context, the value of this
depends on how the function is called. If it is called by a reference object, then this
is set to that object, otherwise the value of this
is set to global object or undefined
(in strict mode).
let foo = {
bar: function () {
console.log(this)
},
}
// 'this' refers to 'foo', because 'baz' is called by the object 'foo'
foo.bar()
let bar = foo.baz
// 'this' points to the global window object because no reference object is specified
bar()
Lexical environment
Lexical environment is a canonical type that defines the association between identifiers and specific variables and functions based on lexical nested structures of ECMAScript code. A lexical environment consists of an environment recorder and a possible null value that references an external lexical environment.
A lexical environment is a structure that holds an identifier-variable map.
Tips
The identifier here refers to the name of the variable/function, which is a reference to the actual object [including the function type object] or the original data.
There are two components inside the lexical environment: (1) Environment recorder and **(2) a reference to an external environment.
- Environment logger is the actual location where variables and function declarations are stored.
- Reference to external environment means it can access its parent lexical environment (scope).
There are two types of lexical environments:
- Global Environment (in the global execution context) is a lexical environment without external environment references. The external environment reference to the global environment is
null
. It has built-in Object/Array/, prototype functions in the environment logger (associated global objects, such aswindow
objects), and any user-defined global variables, and the value ofthis
points to the global object. - In the function environment**, user-defined variables inside the function are stored in the environment logger. And the referenced external environment may be the global environment, or any external function that contains this internal function.
There are two types of environment loggers:
- Declarative Environment Recorder: Stores variables, functions and parameters.
- Object Environment Recorder: Used to define the relationship between variables and functions that appear in the global context.
It can be seen that:
- In the global environment, the environment logger is an object environment logger.
- In function environment, the environment recorder is a declarative environment recorder.
Tips
For function environments, the declarative environment logger also contains a arguments
object passed to the function (this object stores the mapping of indexes and parameters) and length
of the parameters passed to the function.
Use pseudo-code to describe the lexical environment, roughly as follows:
GlobalExecutionContext = {
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Object",
// Bind the identifier here
}
outer: <null>
}
}
FunctionExecutionContext = {
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// Bind the identifier here
}
outer: <Global or outer function environment reference>
}
}
Variable environment
Variable Environment is also a lexical environment whose environment recorder holds the binding relationship created by the variable declaration statement in the execution context.
Variable Environment has all the properties of the lexical environment defined above.
In ES6
, a difference between the lexical environment and the variable environment is that the former is used to store function declarations and variables (let
and const
) bindings. The latter is only used to store var
variable binding.
Sample code:
let a = 20
const b = 30
var c
function multiply(e, f) {
var g = 20
return e * f * g
}
c = multiply(20, 30)
Sample code Execute context pseudocode:
GlobalExectionContext = {
ThisBinding: <Global Object>,
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Object",
// Bind the identifier here
a: < uninitialized >,
b: < uninitialized >,
multiply: < func >
}
outer: <null>
},
VariableEnvironment: {
EnvironmentRecord: {
Type: "Object",
// Bind the identifier here
c: undefined,
}
outer: <null>
}
}
FunctionExectionContext = {
ThisBinding: <Global Object>,
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// Bind the identifier here
Arguments: {0: 20, 1: 30, length: 2},
},
outer: <GlobalLexicalEnvironment>
},
VariableEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// Bind the identifier here
g: undefined
},
outer: <GlobalLexicalEnvironment>
}
}
Warning
The function execution context is created only when the function multiply
is called.
illustrate:
You may have noticed that the variables defined by let
and const
do not have any values associated with them, but the variables defined by var
are set to undefined.
This is because during the creation phase, the engine checks the code to find variables and function declarations, and although the function declarations are completely stored in the environment, the variables are initially set to undefined
(in the case of var
), or are not initialized (in the case of let
and const
).
This is why you can access the variables defined by var
(although undefined
) before the declaration, but accessing the variables of let
and const
before the declaration will get a reference error.
This is what we call variable declaration promotion.
Execution phase
At this stage, all of these variables are completed and the code is finally executed.
Warning
During the execution phase, if the JavaScript
engine cannot find the value of the let
variable in the actual location declared in the source code, it will be assigned as undefined
.