preface

Execution context is a very important concept in JavaScript, involving almost all aspects of knowledge, understanding the execution context can help to understand the running mechanism of JavaScript, many problems can be easily solved. However, execution context is very abstract and hard to observe, so this time we’ll take a look at execution context in JavaScript.

Look at the execution context

Before we can learn, we need to have some concept and understanding of the execution context.

What is an execution context

In short, an execution context is an abstraction of the context in which the current JavaScript code is being parsed and executed, and any code that runs in JavaScript runs in an execution context.

In other words, our code actually runs in context, and the scope and promotion we introduced earlier and the this we will introduce later are all based on the execution context. Therefore, it is necessary to introduce the concept of context. Let’s take a look at the magic of execution context in the next section.

The type of execution context

There are three types of execution context: global execution context, function execution context, and Eval function execution context.

  • Global execution context

There is one and only one global execution context, which is created when JS is first run and added to the execution stack, and removed when exiting the browser.

  • Function execution context

Function execution context can exist countless, when we call a function is created function execution context, but only after the function, the execution and literary talent will be removed, if in the body of the function call other functions, so the context of the other functions will continue to add to the execution stack, knowledge we’ll talk about next to the execution of the stack.

  • The Eval function executes the context

The Eval function execution context means that when Eval is called, a new execution context is created. This is rarely used and is not recommended.

Execution stack of execution context

Earlier, when we introduced scope, we mentioned that internal functions can access variables of external functions. Where are these variables stored? Why are there scope chains?

The answer lies in the fact that the execution context holds the key information we need during JS code execution, and the execution context is stored in a LIFO (LIFO) structured execution stack, or call stack.

Here’s an example:

function outer(){
	console.log(1);
    inner();
}
function inner(){
	console.log(2);
}
outer();
Copy the code

Let’s draw a diagram to illustrate the stack of this code. First, there is a global execution context when we have not executed this code:

As we mentioned above, the function execution context is created when the function is called, so when code executes to:

outer();
Copy the code

At this point we’re going to create oneouterThe execution context of the function is placed on the execution stack, like this:

So when does Outer move out? Outer (outer); inner (outer);

function outer(){
	console.log(1);
        inner();// Call inner
	}
Copy the code

At this timeouterThe function doesn’t finish executing, so we create it againinnerThe execution context of the function looks like this:

Layers of dolls. It’s fineinnerThere’s no more function called in the function body, so it’s going to be done pretty soon, and we’re going to putinnerThe function context is removed from the stack, and the call stack returns to the state we saw in the previous diagram:

releaseinnerAfter the context of the function, we come back toouterIf another function is called in the body of the function, then we will continue to create the context of the other function, but here ourouterThe function is done executing, so let’s call itouterThe execution context of the function is also removed from the execution stack, and eventually our call stack returns to its original state:

The global context remains at the bottom of the stack for the duration of a run and is not removed until the run ends or the browser exits.

To summarize the stack characteristics of the execution context:

  • Created the first time the script is runGlobal contextIs removed on exit
  • Created when the function is calledFunction execution contextAnd added to the top of the stack, where the execution context is the top context
  • When the function completes, the execution context is removed from the top of the stack, pointing to the context at the latest top of the stack

Deep execution context

We just looked at the types and management of execution contexts, but we didn’t look at what the process of creating an execution in an execution context is. What does the execution context include? Let’s explore:

Execution context composition

The execution context can be regarded as three parts, namely the direction of this, the LexicalEnvironment and the VariableEnvironment, which can also be expressed as pseudo-code:

ExecutionContext = {  
  ThisBinding = <this value>, LexicalEnvironment = { ... }, VariableEnvironment = { ... }},Copy the code

Let’s take a look at each part of the function.

This point

The reference to this includes the value of this in this context, also known as this Binding. In JavaScript, the reference to this is dynamic, that is, the value of this is determined during the creation of the execution context and stored in this Binding. The Binding rules for this are complicated and will not be expanded here, but may be introduced separately later.

Lexical environment

Definition of lexical environment

The lexical environment is defined in the official ES6 documentation as follows:

A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code.

In translation, a lexical environment is a canonical type used to define the association of identifiers with specific variables and functions according to the lexical nesting structure of ECMAScript code. In simple terms, a lexical environment is a structure that contains a mapping of identifiers to find the object or function you need. An identifier is a string name, and a variable is the actual stored content. We can get the value of the variable by mapping the identifier string to the lexical context.

Composition of lexical environment

The lexical environment consists of an environment record and possibly empty references to the external lexical environment. Typically, the lexical environment is associated with some particular syntactic structure of ECMAScript code, such as FunctionDeclaration, BlockStatement, or the Catch clause of TryStatement, and a new lexical environment is created each time this code is executed.

Feel similar to the global, function, and block-level scopes of scope and scope? Because lexical context is the implementation mechanism of scope in JS, lexical context is sometimes called lexical scope.

It should be noted that lexical environment can be divided into two types: global environment and function environment, but the content types are the same, including environment records and references to external environment:

  • Environmental records

The actual location where variables and function declarations are stored, and where we can get the values we want.

In a global environment, properties and methods on the global object Window, as well as user-defined global variables, are recorded. In a function context, the main argument is the variables defined in the function, plus a arguments object that contains the mapping between the index and arguments passed to the function, as well as the length (number) of arguments passed to the function.

  • References to the external environment

The referenced value of the external environment, through the reference value of the external environment can form a chain search, layer by layer to search for variables.

In a global environment, the reference value to the external environment is null. In a function context, the reference value to the external context depends on where the function is defined, which may be the external function context or the global context.

Pseudocode representation of lexical environment

Let’s use pseudocode to represent the lexical context in the global and functional contexts:

  • The global environment
GlobalExectionContext = {  
  LexicalEnvironment: {  
    EnvironmentRecord: {  // Environment record
      Type: "Object".// Global variables and function declarations
      }
    outer: <null>  // In a global environment, the reference to the external environment is null}}Copy the code
  • Function of the environment
FunctionExectionContext = {  
  LexicalEnvironment: {  
    EnvironmentRecord: {  // Environment record
      Type: "Declarative".// Variables and function declarations in the function environment
    outer: <Global or outer function>// References to external functions depend on where the function is defined}}Copy the code

Since the environment record in the function environment also includes arguments objects, here’s an example:

function test(a, b) {  
  console.log(arguments); //Arguments: {0: 2, 1: 3, length: 2},
}  
test(1.2);
Copy the code

As you can see, we can output the arguments object directly in the test function. Let’s use pseudocode to represent the lexical environment in this case:

FunctionExectionContext = {  
  LexicalEnvironment: {  
    EnvironmentRecord: {  // Environment record
      Type: "Declarative".arguments: {0: 2.1: 3.length: 2},
    outer: <Global>  // The test function is defined globally, so references to the external environment are global}}Copy the code

We have spent a lot of space and examples to understand the lexical environment, but we have not fully explained all the details in detail. We will make some supplementary and comparative understanding in the following variable environment.

The variable environment

The variable environment is also a lexical environment, so it has all the properties of the lexical environment defined above, so why separate the variable environment from the lexical environment? This is due to differences in the categories of their environmental records. We just said that the lexical context is a structure that contains mapping of identifier variables, and the context record is the actual location where variable and function declarations are stored. So how exactly is this recorded? This is the difference between a variable environment and a lexical environment. Let’s walk through the process separately:

Environment records in a variable environment

The environment record here is only used for binding identifiers and variables declared by var.

  1. The global environmentBinds all identifiers in the environment record towindowObject with the same name

    At this point we executevar name ='window'“Is actually executionwindow.name ='window'.
  2. The global environmentwillwindowObject with all property names bound toEnvironmental recordsOn the identifier of the same name in

    Let’s do it firstwindow.name="2", we’ll find that we can execute it directlyconsole.log(name)The outputwindow.nameThe value of the.
  3. If the identifier is already boundwindow, then the variable is the corresponding attribute value, otherwise the variable is instantiated and assigned toundefined(Variable promotion)
  4. If the identifier already exists, repeatvarThe statement will be ignored

Having looked at the variable environment, let’s look at the lexical environment.

Environment record in lexical environment

The environment record here is used to store function declarations and bindings of identifier variables declared by lets and const.

  1. Identifies all non-var declarationsinstantiation, but does not initialize, leaving the variable inuninitializedState (immutable promotion). That is, the memory has been reserved for variables, but the corresponding identifier has not been bound
  2. Only when the declaration statement is executedInitialize theAnd subsequent assignment operations
  3. Duplicate declarations are not allowed. If they already exist, an error is reported, and the declared identifier cannot be usedvarRestate.
For example

Let’s take a look at an example and see what the two look like using a combination of pseudo-code:

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

The execution context is created when c = multiply(20, 30) is executed.

  • The global environment
GlobalExectionContext = {

  ThisBindingEnvironmentRecord: {Type: "Object", a: <Global Object>, LexicalEnvironment: {//let and const and function declaration stored where EnvironmentRecord: {Type: "Object", a: < uninitialized >, b: < uninitialized >, multiply: < func >} outer: <null>}, VariableEnvironment: EnvironmentRecord: {Type: "Object", c: undefined, //c initialized with undefined} outer: <null>}}Copy the code
  • Function of the environment
FunctionExectionContext = {  
   
  ThisBinding: <Global Object>, LexicalEnvironment: {//let and const and where the function declaration is stored EnvironmentRecord: {Type: "Declarative", // Arguments: {0:20, 1:30, length: 2},}, outer: <GlobalLexicalEnvironment>}, VariableEnvironment: {//var declaration storage place EnvironmentRecord: {Type: "Declarative", g: Outer: <GlobalLexicalEnvironment>}}Copy the code

Creation and execution of the execution context

We spent a lot of time analyzing the execution context, and in the end the creation and execution process was simple:

Create a stage

  1. determinethisThe value of theThis Binding
  2. The LexicalEnvironment component is created
  3. The VariableEnvironment component is created

Execution phase

This is the easiest part of the whole article. At this stage, all variables are allocated and the code is executed.

You’re done

conclusion

This document explains the relevant knowledge of the execution context from simple to deep. The knowledge point is very many and complex, so if there are mistakes or deficiencies in understanding, I hope you can help, I will be very happy (* ̄)  ̄).

Write in the last

  1. Thank you very much to see here seriously, if you think this article is helpful to you might as well click a like to support, thank you ~
  2. More articles and knowledge points will be updated in the future. If you are interested, you can pay attention to a wave of ~

Check out the blog for more information on this topic.

  • Interesting scope and enhancement
  • Let’s play around with closures!

Refer to the article

  • Understand the JavaScript execution context
  • Intensive reading Javascript series (2) Environment Record and lexical environment