preface

It is important to learn JavaScript and understand its internal execution logic. Today’s article will cover JavaScript execution context and execution stack.

JavaScript series: Advanced JavaScript

What are execution context and execution stack?

Execution context

An execution context is an abstraction of the context in which the current JavaScript code is being parsed and executed.

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

type define
Global execution context The default environment created when the program is first run. A program can have only one global context
Function execution context Each time a function is called, a new function execution context is created
The Eval function executes the context inevalThe code executed in a function. Rarely used and not recommended, this article will not cover in detail.

Note: The global context does two things:

  • Define a global object. In the browser, the global object is window

  • Point this to the global object. For a detailed introduction to this, I recommend reading the article to see the five ways this bindings can be used

Execution stack

The execution stack has a stack structure (LIFO last in first out) for storing all execution contexts created during code execution.

  • When a program executes, a global context is created and pushed onto the execution stack. Each time a function is called, an execution context is created for that function and pushed to the top of the execution stack

  • When the function in the stack completes, it pops off the top of the stack, and continues to run the next function in the stack, and so on.

  • When all programs are executed, the Javascript engine removes the global execution context from the execution stack.

So let’s run the case

function first() {
   // Call second
   second();

   console.log('End of execution context for first() function')}function second() {
   console.log('End of execution context for the second() function')}// Call the function
first();

console.log('End of global execution context')
Copy the code

In this case, when executing the program, a global context is created, then the function first() is called to create the execution context push to the execution stack, and second() is called to create the execution context push to the execution stack. Therefore, the program pushes to the execution stack in the following order:

Global execution context => first() execution context => Second () execution contextCopy the code

Second () is popped out of the stack, and first() is popped out of the stack. At the end of the program, the global execution context is popped out. In this case, the order of pop out from execution stack (LIFO last in first out) is as follows:

The lifecycle of the execution context

From the execution stack introduction, we understand how the program manages the execution context. How is the execution context created? Let’s look at the lifecycle of the execution context

The execution context life cycle is divided into three phases: create phase => execute phase => reclaim phase

Create a stage

When a function is called, but before any of its internal code is executed, it is in the creation phase of the execution context.

In the creation stage, we mainly do three things: variable environment (create variable object), lexical environment (create scope chain) and this binding (determine this points to).

1. Lexical environment (create scope chain)

The lexical environment step can also be understood as creating a scope chain.

A lexical environment is a canonical type that defines the relationship of identifiers to specific variables and functions based on the lexical nesting structure of ECMAScript code. Simply put, it is a structure that contains a mapping of identifier variables.

The lexical environment consists of two parts: the environment record and the reference to the external environment.

  • Environmental recordsStore variable and function declarations. Environmental records are divided intoDeclarative environmental records,Object Environment Record,Global environment Record
type define
Declarative environmental records Used to record mappings between identifiers and variables, record onlyThe varDeclared identifier (Let, const, function...), no associated binding object
Object Environment Record Used to record mappings between identifiers and variables, record onlyvarDeclared identifier with an associated binding object
Global environment Record Declarative environmental recordsandObject Environment RecordThe combination of

Let’s look at a classic problem: temporary dead zones

var name = Valley Floor Dragon;
var f = () = >{
   console.log(name);
   let name = 'World beaters';
}
f();
Copy the code

If the variable name is defined outside function f and inside function name is defined using let, an uninitialized error will be reported when the variable name is accessed before let definition.

This is a temporary dead zone phenomenon. What is the cause of this problem? And that relates to the environmental record. Variables defined by the let belong to declarative environment records, have no associated binding objects (that is, reserved memory, but not bound to identifiers), and are in an uninitialized state.

  • References to external environments are used to access their external lexical environment

Lexical environment can be divided into global environment and functional environment

type Environmental records References to the external environment
The global environment Having a global object (window) and its associated methods and properties, and any user-defined global variables,thisThe value points to the global object There is no external environment, the reference to the external environment isnull
Function of the environment The user infunctionVariables defined in the function environment record are stored in the function environment record and contain oneargumentsobject Can beThe global environmentOr it could beExternal function environment

Note: The arguments objects included in the function environment package the index and mapping of the arguments to the function and the length of the arguments. Arguments for the following case are {0:’ valley flying dragon ‘, 1:28, length: 2}

function f(name, age){
   console.log(`my name is ${name}, my age is ${age}`);
}

f(Valley Floor Dragon.28);

// Arguments: {0:' l ', 1: 28, length: 2}
Copy the code

2. Variable environment (create variable objects)

The variable environment step can also be understood as creating variable objects (containing variables, functions, and parameters).

The variable environment is also a lexical environment and has all the attributes of the lexical environment.

In ES6, the difference between variable and lexical environments is that lexical environments are used to store function declarations and variable bindings (let and const); The variable environment is only used to store variable bindings (var)

During the creation phase, the code is scanned and parsed with variable and function declarations, where the function declarations are stored in the environment and variables are set to undefined (in the case of var) or left uninitialized (in the case of let and const).

  • Variable ascension

When creating a variable object, the variable declaration of the execution context (via var) is obtained in turn. If no variable is defined, it is set to undefined by default. This is called variable promotion

console.log(name); / / output is undefined
var name = Valley Floor Dragon;
Copy the code

Use var to define the variable name, which is used before definition and is set to undefined by default.

When the variable is promoted, it corresponds to the following code

var name;
console.log(name); / / output is undefined
name = Valley Floor Dragon;
Copy the code

But if thevartoletorconst, the variable will remain uninitialized and the program will report an error:

  • Function declaration promotion

There are two ways to create a function: function f(){} or var f = function(){}. What’s the difference between these two kinds of function promotion?

console.log('By function declaration:' + f1);
console.log('By variable declaration:' + f2);

// by function declaration
function f1() {}
// By declaring variables
var f2 = function() {}
Copy the code

The result is as follows:

The function declaration can be promoted by creating a function declaration in the same way as the function declaration. The function declaration can be promoted before the function definition. Create a function as a variable declaration, which is called variable declaration promotion. Default is undefined

There is one detail to note: if the function declaration has the same name as the variable declaration, the function declaration takes precedence over the variable declaration when promoted.

// The function is executed before the function definition, mainly in the form of function declaration creation
// Print "Execute function created by function declaration"
f();
// by function declaration
function f() {
   console.log('Execute a function created by a function declaration')}// By declaring variables
var f = function() {
    console.log('Execute function created by variable declaration')}// Execute the function after the function definition, using the recently created declaration (in this case, the variable declaration)
// Print "Execute function created by variable declaration"
f();
Copy the code

3. This binding (make sure this points to)

The this binding, in fact, determines what this refers to. Check out my article on five ways to bind this

  • In the context of global execution,thisIt’s bound to the global object, and in the browser, the global object iswindow
  • In the context of function execution,thisThe value of the binding depends on the object on which the function is called. If it is called by an object reference, thenthisIs set to the object, otherwisethisIs set to a global object orundefined(In strict mode)

Execution phase

The execution phase completes the allocation of all variables and finally executes the code.

At execution time, the JavaScript engine assigns undefined to the let variable if it cannot find the value at the actual location declared in the source code

Recovery phase

The execution context is removed from the stack and waits for the VM to reclaim the execution context

conclusion

It took three days to compile. If you like this article, please give it a thumbs up

Welcome to follow my public number “flying dragon at the bottom of the valley” ~

Reference:

  • In-depth understanding of JavaScript execution context and execution stack
  • Environment record and lexical environment