This is the fifth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Execution context

Simply put, an execution context is an abstraction of the context in which Javascript code is executed. Whenever Javascript code is running, it must be running in the execution context

There are three types of execution context:

  • Global execution context: There is only one, and the global object in the browser is the Window object to which this refers

  • Function execution contexts: There are an infinite number of them, which are created only when the function is called. Each time the function is called, a new execution context is created

  • Eval function execution context: Code that runs in an Eval function is rarely used and not recommended

Examples of global and function contexts are given below:

The global context is framed in purple, and the different function contexts are framed in blue and orange. Only the global context can be accessed by any other context

You can have any number of function contexts. Each time you call a function to create a new context, a private scope is created. Any variables declared inside the function cannot be accessed directly outside the scope of the current function

The life cycle

The lifecycle of an execution context consists of three phases: creation → execution → reclamation

Create a stage

The create phase is when a function is called but before any of its internal code is executed

The build phase did three things:

  • Determines the value of this, also known as this Binding

  • The LexicalEnvironment component is created

  • The VariableEnvironment component is created

The pseudocode is as follows:


ExecutionContext = {  
  ThisBinding = <this value>// This LexicalEnvironment = {... }, // lexical environment VariableEnvironment = {... }, // variable environment}Copy the code

This Binding

Determine the value of this. As we mentioned earlier, the value of this is only validated at execution, not at definition

Lexical environment

The lexical environment has two components:

  • Global: is a lexical environment that has no external environment, whose external environment reference is NULL and has a global object to which the value of this refers

  • Function environment: The variables defined by the user in the function are stored in the environment record, which contains the Arguments object. References to the external environment can be global or an external function environment containing internal functions

The pseudocode is as follows:

GlobalExectionContext = {  // Global execution context
  LexicalEnvironment: {       // Lexical environment
    EnvironmentRecord: {     // Environmental records
      Type"Object".// Global environment
      // The identifier is bound here
      outer: <null>           // References to the external environment
  }  
}

FunctionExectionContext = { // Function execution context
  LexicalEnvironment: {     // Lexical environment
    EnvironmentRecord: {    // Environmental records
      Type"Declarative".// Function environment
      // The identifier is bound here // a reference to the external environment
      outer<Global or outer function environment reference>}}Copy the code

The variable environment

The variable environment is also a lexical environment, so it has all the attributes of the lexical environment defined above

In ES6, lexical environments differ from variable environments in that the former is used to store function declarations and variable (let and const) bindings, while the latter is used only to store variable (var) bindings

For example

let a = 20;  
const b = 30;  
var c;
function multiply(e, f{  
 var g = 20;  
 return e * f * g;  
}

c = multiply(20.30);
Copy the code

Execution context is as follows:

GlobalExectionContext = {
  ThisBinding: <Global Object>, LexicalEnvironment: {// EnvironmentRecord: {Type: "Object", // identifier bound here a: < uninitialized >, b: < uninitialized >, multiply: < func > } outer: <null> }, VariableEnvironment: {Type: "Object"} outer: {Type: "Object"} outer: {Type: "Object"} outer: <null> } } FunctionExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: { EnvironmentRecord: { Type: Argumentative: {0: 20, 1: 30, length: 2},}, outer: <GlobalLexicalEnvironment>}, VariableEnvironment: {EnvironmentRecord: {Type: "Declarative", // undefined }, outer: <GlobalLexicalEnvironment> } }Copy the code

Notice in the code above that variables a and b defined by let and const are not assigned during the creation phase, but variables declared by var are assigned to undefined from the creation phase

This is because during the creation phase, variables and function declarations are scanned in the code, and then the function declarations are stored in the environment

However, variables are initialized to be undefined(with var declarations) and uninitialized(with let and const declarations).

This is the actual reason for the variable to rise

Execution phase

At this stage, variable assignment and code execution are performed

If the Javascript engine cannot find the value of the variable at the actual location declared in the source code, then undefined is assigned to it

Recovery phase

The execution context is off the stack waiting for the VIRTUAL machine to reclaim the execution context

Execution stack

The execution stack, also called the call stack, has a LIFO (last in, first out) structure that stores all execution contexts created during code execution

When the Javascript engine starts executing your first line of script code, it creates a global execution context and pushes it onto the execution stack

Whenever the engine encounters a function, it creates a function execution context and pushes this execution context onto the execution stack

The engine executes the execution context at the top of the execution stack (usually a function execution context), and when that function is finished, the corresponding execution context is popped, and the control flow reaches the next execution context on the execution stack

Here’s an example:

let a = 'Hello World! ';
function first({
  console.log('Inside first function');
  second();
  console.log('Again inside first function');
}
function second({
  console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');

Copy the code

I’m going to turn it into a graph

A brief analysis of the process:

  • To create a global context, push the execution stack

  • The first function is called to create the function execution context and push the stack

  • The second function is encountered during the first function execution, and another function execution context is created and pushed

  • After the second function is executed, the corresponding function execution context is pushed out of the execution stack and the next execution context, first function, is executed

  • After the first function is executed, the corresponding function execution context is pushed off the stack, and then the global context is executed

  • When all code is executed, the global context is pushed off the stack and the program ends