Execution context
1. Execute the context stack
Take a look at the execution context lifecycle
Js execution context is a basic concept, ** execution context is the current code running environment, the running environment mainly includes the global environment and function environment, ** in-depth understanding of the execution context to understand the function scope chain, variable promotion, closure is very good
The Execution Context Stack follows the last in, first out principle and manages the Execution Context. When THE JS code is executed, the global environment is first entered, and the global Context is created and added to the Stack. When the corresponding function environment is entered, the function Context is created and added to the Stack. When the function code completes execution, the stack is removed
function A() {
B()
}
function B() {
}
A()
Copy the code
We can look at Yamashita bunji in pseudocode
Ecstack. push(global_EC) // A is called ecstack. push(A_EC) // B is called, Pop () // ecstack.pop () // global context ecstack.pop ()Copy the code
2. Composition of execution context
There are three important properties in the execution context, Variable Object, scope chain, and this(this binding), which we can express as
EC = {
VO,
SC,
this
}
Copy the code
The lifecycle of the execution context is the creation and execution phases, respectively.
- The creation phase is mainly to generate the variable object, establish the scope chain, and determine the this point
- The execution phase is mainly variable assignment and code execution
1. Variable Object
Creating a context is a three-part process
-
Retrieves the Arguments of the current context: Generate Arguments objects and change the parameter name to the property name and the property value to the parameter
-
Retrieves the function declaration of the current context, the function name is the property name, and the reference address of the function is the property value
-
Retrieves the variable declaration of the current context with the name of the property, undefined being the value of the property
VO = {Arguments: {}, ParamVariable: Function:, ParamVariable: undefined}
When the context reaches the execution stage, the variable Object becomes an Active Object and the declared variable is assigned a value
Let’s take a practical example
function A(p) {
var a = 1
function B() {}
var c = function () {}
}
A(0)
Copy the code
The context creation phase of such a code generation is
A_EC = {
VO = {
arguments: {
'0': 0,
length: 1
},
p: 0,
a: undefined,
B: <function B reference>,
c: undefined
}
}
Copy the code
In the execution phase of A
A_EC = {
VO = {
Arguments: {
'0': 0,
length: 1
},
p: 0,
a: 1,
B: <function B reference>,
c: <function express c reference>
}
}
Copy the code
This is the internal mechanism of function promotion and variable promotion
var a = 1
function A() {
}
Copy the code
In fact, the order in which JS is created can be understood as
function A() {}
var a = undefined
a = 1
Copy the code
2. Scope chain
Scope chain refers to a series of variables in the current context and upper context object hierarchy consisting of a chain, it ensures that the current execution environment can access which variables and functions, when you need to find a variable or function, will find in the current context of the variable object, if not found, will be along the upper context variable object to look up, know to find the global context
Js scope includes global scope and function scope. Function scope is determined when the function is declared. Each function will contain a [[scope]] internal attribute
Function A () () {} {the function B B ()} () / / B of the [[scope]] create stage B. [[scope]] = [A_EC. VO, globalObj]Copy the code
When B is called, its execution context is created and added to the stack, which adds the generated variable object to the top of the scope chain
B.[[scope]] = [B_EC.VO, A_EV.VO, globalObj]
Copy the code
3. This point
The reference to this is determined when the function is called
You can read my previous article
Juejin. Cn/post / 693903…
Several cases of this are explained
4. The closure
When the context is removed from the stack, the corresponding variable object is collected by the garbage collection mechanism. There are two ways to collect js garbage
- Reference counting: This is a simple determination of whether an object points to another reference. If it does not, it will be recycled. If it does, it will not be recycled
- Mark clearing: Periodically scan the objects in memory from the root object, and mark the objects that are not in use as unreachable objects. You can meditate on garbage collection
Closures, however, prevent variable objects from being recycled
A closure is a function that has access to internal variables, understood in execution context terms, meaning that the current execution context is off the stack, but the current variable object can still be accessed
function A() {
var a = 1
function B() {
var b = a + 1
}
return B
}
A()()
Copy the code
You can see from the top
The [[scope]] / / B can be expressed as b. [[scope]] = [B_EC. VO, A_EC. VO, global VO]Copy the code
So the scope chain of context B contains variable objects of context A, and B accesses variable objects of context A, preventing garbage collection of variable objects of context A
Let’s take a classic example
var arr = []
for(var i=0; i < 3; i++ ) {
arr[i] = function() {
console.log(i)
}
}
arr[0]()
arr[1]()
arr[2]()
Copy the code
To examine the example, the global context can be represented as
global_EC = {
VO: {
arr,
i: 3
}
}
Copy the code
This is when arr[0] is called in context
arr[0]_EC: {
VO: {
},
scope: [arr[0]_EC.VO, global_EC.VO]
}
Copy the code
Arr [0]_EC has no I variable, so it can only be found in global_EC. I = 3, so arr[1]() and ARr [2] are all global I. Before let,a classic solution was closure
var arr = [] for(var i=0; i<3; i++) { arr[i] = (function(i) { return function() { console.log(i) } } )(i) }Copy the code
So let’s analyze it again, arr[0]_EC
Arr [0] _ec. scope = [arr[0] _ec. VO, anonymous function _ec. VO, golbal_ec.vo]Copy the code
And the VO of anonymous functions is
Function _ec. VO = {Arguments: {'0': 0, length: 1}, I: 0}Copy the code
At this time, arr[0] has no I in VO, but according to the scope chain found the I of VO in the anonymous function, so it can return the expected result
Of course, you can also use let in ES6
var data = []
for( let i = 0; i<3; i++) {
data[i] = function() {
console.log(i)
}
}
Copy the code
The block-level scope of the LET declaration can be thought of as an execution context, which can be seen as
{
let i = 0
data[0] = fucntion() {
console.log(i)
}
}
Copy the code
Data [0] can be regarded as the closure of the scope generated by the let, referring to I of the block-level scope, so the value of I can be obtained