When we learn about scopes or closures, we can’t get around the terms execution context, execution stack, etc. So what is execution context?

What is the execution context

Execution Context (EC). There are a lot of descriptions on the web about the definition of an execution context, which is simply a scope, which is the environment in which this JavaScript code is run.

Composition and classification of execution context

Of 1.

For each execution context EC, there are three important properties:

  1. Variable Object (Variable declaration, function declaration, function parameter)
  2. Scope Chain Scope Chain
  3. This pointer

Classification of 2.

Execution contexts fall into three categories

  1. Global execution context
  2. Function execution context
  3. Eval Execution context (rarely used, not explained for now)

[Global execution Context]

The term understand

The environment into which code is first entered before execution begins.

The characteristics of

There is one and only one global execution context. The window object is typically created by the browser on the client side.

Pay attention to the point

(1) All global variables declared by var can be accessed in the Window object. It can be understood that window is the carrier of the var declaration object.

(2) Global variables declared by let cannot be accessed by window objects.

[Function execution context]

The term understand

When a function is called, a function execution context is created.

The characteristics of

There can be more than one function execution context, and a new function execution context is created even if the call itself is called.

This is the difference between a global execution context and a function execution context.

Let’s look at the lifecycle of the execution context.

Lifecycle of execution context

The lifecycle of an execution context can be divided into three phases:

  1. Create a stage
  2. Execution phase
  3. Recovery phase

1. Creation phase

Occurs when a function is called, but before the internal code is executed.

The creation phase mainly does the following:

Create a Scope Chain. (3) Confirm that this refers to this Binding

Let’s start with code to get a more intuitive understanding of the creation phase:

function foo(i){
    var a = 100;
    var b = function(){};
    function c(){}
}
foo(20);
Copy the code

When foo(20) is called, the execution context is created as follows:

ExecutionContext:{
    scopeChain:{ ... },
    this:{ ... },
    variableObject: {arguments: {0: 20.length: 1
        },
        i: 20.c: <function>,
        a:undefined.b:undefined}}Copy the code

2. Implementation phase

After creation, the program automatically enters the execution stage, and the main tasks in the execution stage are as follows:

(1) Assign values to variable objects: assign values to variables in VO and function expressions. (2) call function (3) execute code sequentially

Taking the above code as an example, VO is assigned at the execution stage, which is represented by pseudo-code as follows:

ExecutionContext:{
    scopeChain:{ ... },
    this:{ ... },
    variableObject: {arguments: {0: 20.length: 1
        },
        i: 20.c: <function>,
        a: 100,b:function}}Copy the code

3. Recycling phase

After all code is executed, the program is closed and memory is freed.

After the context is removed from the stack, the VM is reclaimed. The global context is only pushed when the browser is closed.

The creation of execution context requires the creation of variable objects. What are variable objects?

Variable object VO and active object AO

1. Understand the VO concept

Variable Object, VO for short. An object that holds the variables and functions of the global execution context.

VO === this === Global

VOTwo special cases of:

(1) Variables that are not declared by var do not exist in VO. (2) function expressions (as opposed to function declarations) do not exist in VO

2. Understand the concepts of AO

An Activation Object, also called an Activation Object, or AO for short.

The activation object is created when the function execution context is entered (the moment before the function is executed).

In the context of function execution, VO is not directly accessible, so AO plays the role of VO.

VO === AO, and adds the parameter class array and the parameter values

Arguments Object Is an Object in the function context AO, which contains attributes such as: (1) Callee: a reference to the current function (2) Length: the number of Arguments actually passed (3) properties-indexes: Parameter values of the function (from left to right in argument list)

3. VO initialization process

(1) Create and initialize arguments based on function arguments

Variable declarations var, function parameters, function declarations

(2) Declaration of scanning function

A function declaration is an attribute of a variable object whose property name and value are created by the function object. If the variable object already contains a property of the same name, it replaces its value.

(3) Scan variable declarations

A variable declaration is a property of a variable object whose property name is the name of the variable and whose value is undefined. If the variable name is the same as the declared function name or the parameter name of the function, existing attributes are not affected.

Note: Function declarations take precedence over variable declarations

5. Example analysis

1. Replace the value of a variable object if it already contains attributes of the same name.

To understand this in code:

function fun(a){
    console.log(a); // function a(){}
    function a(){}
}
fun(100);
Copy the code

We called fun(100) and passed in a value of 100. Why is the result not 100 after the console statement? Don’t worry, let’s continue our analysis

Creation phase:

steps1-1: Created based on the parameterarguments, is assigned to the corresponding parameter by an argument. If no argument is assigned toundefined
AO_Step1: {arguments: {0: 100.length:1
    },
    a: 100} steps1-2: scan the function declaration, then find the function declaration named A, add it to the AO, replace the existing same attribute name a, that is, replace the value of parameter a.AO_Step2: {arguments: {0: 100.length:1
    },
    a: point tofunction a(){}} steps1-3: No variables are found in the variable declaration.Copy the code

Execution stage:

steps2-1: No assignment statement, first line executedconsoleCommand, and now a points to funciton, so outputfunction a(){}
Copy the code

If the variable name is the same as the function name or the parameter name of the function already declared, the existing attribute will not be affected.

So let’s think about it in code

Scenario 1: Variable and parameter names are the same

function fun2(a){
    console.log(a); / / 100
    var a = 10;
    console.log(a) / / 10
}

fun2(100);

// Analysis steps:Creation phase: Steps1-1: according to theargumentsCreate and initialize the AO AO = {arguments: {0: 100.length:1
    },
    a:100} steps1-2There is no additional function declaration, so the AO is the same as last time AO = {arguments: {0: 100.length:1
    },
    a:100} steps1-3: Scans the variable declaration and finds that the A attribute already exists in the AO, so the existing attribute is not modified. AO = {arguments: {0: 100.length:1
    },
    a:100} Execution phase: steps2-1: Execute the commands in sequenceconsoleStatement, where a in the AO is100, so output100.steps2-2: Executes the assignment statement and assigns a to the AO, where a is10. steps2-3: Execute in sequenceconsoleStatement, where a is10, so output10.Copy the code

Scenario 2: Variable and function names are the same

function fun3(){
    console.log(a); // function a(){}
    var a = 10;
    function a(){}
    console.log(a) / / 10
}
fun3();

// Analysis steps:Creation phase: Steps1-1: according to theargumentsCreate and initialize the AO AO={arguments: {length:0}} steps1-2: scans the function declaration, where a points to the function declaration (Function Declaration)
AO={
   arguments: {length:0
   }, 
   a: FD} step1-3: Scans the variable declaration and finds that attribute A already exists in the AO. AO={arguments: {length:0
   }, 
   a: FD} Execution stage: step2-1: Executes the first statementconsole, where a refers to the function declaration, so output the function declaration. AO={arguments: {length:0
   }, 
   a: FD} step2-2} : execute the second sentence to assign the variable object in AO, so the value of a is changed to10. AO={arguments: {length:0
   }, 
   a: 10} steps2-3The function declaration will not be added to the AO during the execution phase. So AO is the same as last time. AO={arguments: {length:0
   }, 
   a: 10} steps2-4: Execute the fourth sentence, where a is10, so output10. AO={arguments: {length:0
   }, 
   a: 10
}
Copy the code

Based on the above examples, we have a rough idea of the EC and its life cycle.

Also, we know that each call to a function creates a new function execution context.

So what if there are multiple execution contexts, how does JavaScript execute?

This involves the knowledge of executing the context stack.

Implement the context stack

1. Understanding of terminology

Execution Context Stack (ECS).

The execution context stack consists of several execution contexts. Also called execution stack, call stack.

2. The role

Used to store all context during code execution.

Characteristics of 3.

We know that the stack is characterized by first in, last out. You can think of it as the bottle, the thing that comes first is always at the bottom.

so

The execution context stack is characterized by LIFO (Last In First Out)

Last in, first out.

4. Storage mechanism

  1. When JS is first executed, the global execution context is put at the bottom of the stack, so the global execution context is always at the bottom.
  2. When a function is called, a new function execution context is created and stored on the execution stack.
  3. The top of the stack is always in the current execution state, and when the execution is complete, the stack is removed and the next execution begins.

5. Example analysis

So let’s make it simple in code

Example 1:

function f1(){
    f2();
    console.log(1)}function f2(){
    f3();
    console.log(2)}function f3(){
    console.log(3)
}
f1(); / / 3 2 1
Copy the code

According to the characteristics of the execution stack:

ECStack=[globalContext]; ECStack=[globalContext];

(2) call f1() function, enter f1 function execution, create f1 function execution context, store in the execution stack, namely, ecstack.push (‘f1 context’)

Push (‘f2 context’). F1 cannot execute the console statement until f2 is executed

(4) F2 calls f3() internally, so f3’s function execution context is created and stored in the execution stack, namely ecstack. push(‘ F3 context’). F2 cannot execute the console statement until f3 completes execution

(5) f3 completes execution, outputs 3, and exits the stack, ecstack.pop ()

(6) f2 complete, output 2, and exit stack ecstack.pop ()

(7) ecstack.pop ()

(8) Finally, ECStack only has [globalContext] global execution context

Example 2:

function foo(i){
    if(i == 3) {return 
    }
    foo(i+1);
    console.log(i) 
}
foo(0); / / 2 0
Copy the code

Analysis:

(1) call foo, create function execution context foo, store EC, pass 0, I =0, if condition not met do not execute,

(2) Execute to foo(1), call foo again, create a new function execution context, store EC, at this time pass I is 1, if condition is not met do not execute,

(3) Execute to foo(2), create a new function execution context, store in EC, at this time I is 2, if the condition is not met, do not execute

(3) Execute to foo(3), create a new function execution context again, store in EC, I is 3, if satisfies exit, EC pop-up foo(3)

(4) EC ejects foo(3) and executes the rest of the code for foo(2), outputs 2, foo(2) is done, EC ejects foo(2)

(5) EC ejects foo(2), executes the rest of the code for foo(1), prints 1, foo(1) is done, EC ejects foo(1)

(6) EC pops foo(1), executes the rest of the code for foo(0), prints 0, foo(0) completes execution, EC pops foo(0), and EC only has the global execution context left.

Seven,

  1. There is only one global execution context and it is at the bottom of the stack.
  2. The global execution context is not on the stack until the browser is closed.
  3. There can be more than one function execution context, and a new function execution context is generated every time a function is invoked (even by itself).
  4. JSIt’s single threaded, so it’s synchronous execution, and the execution context stack, the one that’s always at the top of the stack is the execution state.
  5. VOorAOThere is only one, which is created in the following order: parameter declaration > function declaration > variable declaration
  6. eachECCan be abstracted as an object containing three properties: scope chain,VO/AO,this