The following contents are personal understanding in the study of personal income, if there are mistakes in understanding welcome to point out, thank you. I am just a chicken in learning

What is an execution context?

Definition of execution context

  • ECMA – 262 standard
    • An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript. implementation. At any point in time, there is at most one execution context per agent that is actually executing code. This is known as the agent’s running execution context. All references to the running execution context in this pecification denote the running execution context of the surrounding agent.
  • The translation
    • The execution context is a canonical device that is used to track runtime evaluations by an ECMAScript code. The implementation. At most one execution context per agent is actually executing code at any one time. This is called the execution context of the agent. All references to the running execution context this pecification represents the running execution context of the surrounding agent.

The above is the official explanation of the execution context, the translation is youdao translation, I became more confused after reading it. But after querying many articles and materials written by other big names on the Internet, I got an explanation of the more colloquial points about the execution context

  • The execution context refers to information about variables, function declarations, arguments, scope chains, this, etc. The execution context can be abstracted as an Object.

Therefore, we can briefly understand the execution context as the environment in which the current JS code is running, which holds some information about the code running.

Classification of the execution context

In JS, there are several types of execution context

  • Global execution context
    • There is only one global execution context
  • Function execution context
    • Each time a function is executed, a new function execution context is created
  • Eval Execution context
    • The eval function is rarely used during development

The details of the execution context

According to the definition, the execution context is abstracted into an object in JS. If it is an object, then it naturally has some properties associated with it. For the execution context, it consists mainly of the following

  • Variable Object (OV)
    • Global variable object
    • Function variable object
      • Parameter the arguments
      • Function declaration (replaces existing variable objects)
      • Variable declarations (do not replace parameters and functions)
  • Scoped chain
  • this

The lifecycle of the execution context

The life cycle of an execution context consists of two phases, each of which contains different content

  • Create a stage
    • Creating a variable object
    • Create scope chains
    • Make sure this points to
  • Execution phase
    • Variable assignment
    • A function call
    • Execute other code

Execution Context Stack (ECStack)

As mentioned earlier, execution contexts fall into three categories: global execution context, function execution context, and eval execution context (not normally used). How are these execution contexts managed when JS code is executed? This is where the execution context stack is used! When JS starts to interpret execution code, the first thing it encounters is global code, so the global execution context is pushed onto the execution context stack at initialization. As mentioned earlier in the function execution context, each time a function is executed, a new function execution context is created, and the new execution context is pushed onto the execution context stack. When the function completes, the function execution context is ejected from the stack. When all code is executed, the global execution context is popped and the execution context stack is cleared. Let’s take a look at the process in detail with a piece of code

function foo1(){
    function foo2(){
    }
    foo2();
}
foo1();
Copy the code

The global execution context is pushed when the code begins to interpret execution, and is represented here by globalConetext. The ECStack contents are as follows:

ECStack = [
    globalContext
]
Copy the code

Next, the code creates the foo1 function declaration and executes the foo1 function, so an execution context for the foo1 function is generated and pushed onto the stack. The contents of the execution context stack are as follows:

ECStack = [
    foo1Context,   // Put foo1Context before globalContext just to show that foo1Context is now at the top of the stack
    globalContext
]
Copy the code

After that, the code will go inside the foo1 function and start executing foo1. In the foo1 function, we will call foo2 and execute it, so foo2 will create a context for the foo2 function to execute, and then it will be pushed onto the stack. The contents of the execution context stack are as follows:

ECStack = [
    foo2Context,
    foo1Context,
    globalContext
]
Copy the code

After foo2 completes execution, the execution context created by foo2 will pop out of the execution context stack as follows:

ECStack = [
    foo1Context,
    globalContext
]
Copy the code

Similarly, foo1Context is ejected after the foo1 function has been executed until the code is complete and the globalContext is ejected from the stack, at which point the stack is cleared. The entire flow of executing the context stack is as follows:

ECStack.push(globalContext)
ECStack.push(foo1Context)
ECStack.push(foo2Context)
ECStack.pop(foo2Context)
ECStack.pop(foo1Context)
ECStack.pop(globalContext)
Copy the code

Variable objects (VO) and Active objects (AO)

In the execution context, the execution context contains three contents: the variable object (OV), the scopeChain (scopeChain), and this. To understand why a variable is promoted, it is important to understand the variable object in the execution context. First of all, what is a variable object (VO)? What is an active object (AO)?

VO: Variable Object

Each execution context (execution context) has a corresponding variable object (VO) that holds functions and variables in the current code context (execution context). During code execution, if the value of a variable needs to be queried, it will be queried in the variable object. There are a few things to keep in mind when learning about variable objects:

  • When JS starts to run JS scripts, the global execution context is entered by default, so a global variable object is created, which is the Window object.
  • The global variable object code is directly accessible, but the variable object created by the function is not and needs to be accessed through the active object (AO).
  • Function expressions are not included in VO.

Active Objects (AO: Activation Object)

Because the variable object in the function execution context cannot be accessed directly, an active object is created immediately after the function is created and used as a variable object. An active object can be understood as a representation of a variable object in the context of function execution. The active object is initialized using the arguments property of the function and then, just like the variable object, scans the variable declarations and function declarations in the current environment and creates the corresponding contents.

Scope chains and this (digging)

These are two more big holes, and we’re talking about execution context and variable promotion. In variable promotion, you don’t need to know much about scoped chains and this, just that there are two things in the execution context besides variable objects. Let’s return to the topic of variable promotion! Take a closer look at variable promotions and why they happen.

Variable promotion (as)

What is variable promotion

First, let’s understand what variable promotion (MDN) is as follows:

In the literal sense of the concept, “variable promotion” means that declarations of variables and functions are moved to the front of the code at the physical level, but this is not accurate. The actual location of variable and function declarations in the code is not moved, but is put into memory at compile time.

As you can see, the main content of variable promotion is that when we execute JS code, the declarations of variables and functions (note: only the declarations of variables and functions are promoted) are moved to the front of the code. We can take an example to illustrate this problem:

s = "Hello ";
foo(s);
function foo(a){
    n = "JavaScript";
    console.log(a+n);
    var n;
}
var s;
Copy the code

The execution results are as follows:

PS D:\Code\LESSON_SS\js> node .\hoisting.js
Hello JavaScript
Copy the code

By running the above code, we find that during code writing, we put the code that the function executes before the function declaration, and the variable assignment before the variable declaration, but the code works and outputs what we want. It seems that the code has been changed to the following form:

var s;
s = "Hello ";
function foo(a){
    var n;
    n = "JavaScript";
    console.log(a+n);
}
foo(s);
Copy the code

So what happens between when the code is written, saved to a.js text file, and when our code is compiled and executed, so that we can use variables or functions and then declare functions? Let’s take a closer look at exactly when a variable is promoted.

View variable promotion from execution context

Before variable promotion, we spent a lot of time to understand what the execution context is, what it has, what its life cycle is, and what it has to do with variable promotion. Let’s take that simple piece of code and dive into it.

Code:

s = "Hello ";
foo(s);
function foo(a){
    n = "JavaScript";
    console.log(a+n);
    var n;
}
var s;
Copy the code

First, when JS executes, it creates a global execution context by default and pushes it into the ECStack.

ECStack.push(globalContext)
Copy the code

At this point, the ECStack (execution context stack) looks like this:

ECStack = [
    globalContext
]
Copy the code

So what’s in this globalContext? As we mentioned earlier, there are three main things in an execution context: variable objects, scope chains, and this. Leaving scoped chains and this out of the way, let’s take a look at variable objects, which are created during the creation phase of the execution context. In the creation process of variable objects, the following process is the main.

  1. Start by creating a variable object
  2. Scan the variable declaration and assign the initial value to undefined. As follows:
globalVO = {
    s: undefined
}
Copy the code
  1. Since this is global, we don’t have to deal with arguments, so we start looking for function declarations. Use the function name as the VO object property name and the function body as the VO property value.
  2. The global VO creation is complete. VO is as follows:
globalVO = {
    //foo is a reference to function foo(){}
    foo: reference to function foo(){},   // Function declarations take precedence over variable declarations
    s: undefined
}
Copy the code

The Js engine will query the global variable object (VO) for variable S and assign the value of “Hello Js” to variable S. That’s why we write the assignment statement of S and then the declaration of S. In the same way that foo(a) can execute normally, the function declaration is already stored in the variable object when the execution context is created before the code is executed. JS can find function foo in the variable object of the execution context.

Then, as the code continues to execute, we call function foo (just calling the function, but not executing the code inside the function), which creates the corresponding execution context of the function, and the execution context of the function also contains the above three things. In this case, the ECStack does the following:

ECStack.push(fooContext)
Copy the code

The results are as follows:

ECStack = [
    fooContext,
    globalContext
]
Copy the code

The AO object of the function is also created as follows:

  1. Create the function AO object
  2. Find the parameter and variable variable declarations and assign the value to undefined. As follows:
fooAO = {
    a: undefined.n: undefined
}
Copy the code
  1. Unify the argument and parameter, and get the following result:
fooAO = {
    a: "Hello ".n: undefined
}
Copy the code
  1. The function declaration is then scanned. No function declaration exists for the current function, so the active object is created and the result is the result obtained in step 3.

After the creation phase of the execution context of the function, the code is executed. Similarly, when the assignment operation n = “JavaScript” is performed, the variable n in the active object of the execution context (i.e., the activated variable object OV) is assigned the value “JavaScript. Console.log (a+n) then finds the variables A and N we need in the activated variable object (the live object) and prints them out. After that, the function terminates and the execution context of the function goes off the stack. The result is:

// After the ecstack.pop (fooContext) operation
ECStack = [
    globalContext
]
Copy the code

Finally, the script is complete and the ECStack is empty. Code execution is complete. The overall flow of executing the context stack is as follows:

At this point, we finally have a better understanding of variable promotion, which occurs when code creates an execution context before execution, and the execution context adds function declarations and variable declarations from the current code to the variable object of the execution context during creation. When code executes, if it encounters a lookup for a variable, it looks in the variable object in the execution context of the current code. So when we write code, we can use it first and declare it later (although good code writing habits are always better).

A little question

What should be the result of executing the code below?

showName();
var showName = function(){
    console.log(2)}function showName(){
    console.log(1)
}
showName();
Copy the code

The answer:

PS D:\Code\LESSON_SS\BATJTMD\tecent> node .\1.js
1
2
Copy the code

Reason: We analyze code execution step by step:

  1. The code starts executing and creates the global execution context. At this point in the creation phase of the global execution context, the variable object contents of the global execution context should be as follows:
globalVO = {
    showName: reference to function showName(){...}
}
Copy the code

Where, one might say, did var showName’s statement go? ShowName: undefined

Var showName = function(){var showName = function(){… } is a function expression where the showName variable is declared and the assignment is done at execution time.

So since function declarations take precedence over variable declarations, variable declarations are overridden by function declarations.

  1. The first code to execute is showName(), which calls showName. In the variable object, showName is already declared as a function, so it will execute console.log(1). It then completes and returns to the global execution context.

  2. Var showName = function(){… }. If you don’t understand the previous relationship, you might think that the var showName declaration has been overridden and not execute this line of code. Var showName is overwritten, but the assignment will continue as usual. So this line of code is essentially the same thing as

// showName is already declared as a function
showName = function(){
    console.log(2)}Copy the code
  1. In step 3, the contents of the showName function have been modified, so in the last lineshowName(), the output should be 2.

conclusion

Variable promotion is ostensibly the way all function and variable declarations are promoted to the top during code execution. In essence, it is because the execution context will first add the function variable declaration of the current code to the variable object of the execution context in the creation stage, and in the execution stage, some variables are searched in the variable object, so there is a variable promotion function when the code is compiled and executed.

References:

  • Understand the execution context of JavaScript
  • Execution context and scope
  • Thoroughly understand the scope, execution context
  • About variable objects and active objects in javascript
  • The execution context and environment of JavaScript
  • Execution context and variable objects in JavaScript