An article read JS execution context

 One ❀ lead

We all know that the order of execution JS code will always be different from the order of the code, the head aside asynchronous issue you will find that even the synchronization code, its execution is also inconsistent with your expectations, such as:

function F1 () { 
    the console.log ( 'hear the wind wind' ); 
}; 
F1 (); // echo 

function F1 () { 
    the console.log ( 'echo' ); 
}; 
F1 (); // echo

According to the code written order, the output should first hear the wind is the wind, and then output echo fishes, unfortunately, the two outputs are echo; if we will be in the code above function declaration function expression changed , the results are not the same:

var F1 = function () { 
    the console.log ( 'hear the wind wind' ); 
}; 
F1 (); // hear the wind is the wind 

var F1 = function () { 
    the console.log ( 'echo' ); 
}; 
F1 (); // echo

This shows that the code must have happened some subtle changes prior to execution, JS engine actually done anything at all? This must mention the JS execution context.

 II ❀ JS execution context

JS code before execution, JS engine always do some preparation work, in fact, the job is to create a corresponding execution context;

Execution context and only three categories, global execution context, the function context, and eval context ; eval is generally not due to the use, not discussed here.

1. The global execution context

Only a global execution context, the client is generally created by the browser , and is known window object, we have direct access to it through this.

Global object window on a number of predefined methods and properties, we can directly access these methods in any property at the global environment, while the window object or support global variables var statement . We var created by global object, can be accessed directly through the window.

2. The function execution context

Function execution context there can be numerous, whenever a function is called creates a function context; Note that, by calling the same function will create a new context .

Having said that you will want different types of context, and the number is still so much to create a relationship between how they are, but also who is going to manage the context of it, which had to talk about the execution context stack.

 Triple ❀ execution context stack (execution stack)

Execution context stack (hereinafter abbreviated execution stack), also known as the call stack, execution stack for all contexts created during the execution code stored , the LIFO characteristic having (a rear advanced Last In First Out) of.

JS code first run, will create a global execution context and pressed into the execution stack , then whenever a function is called, will create a new function execution context and pressure in the stack; due to the characteristics of the execution of LIFO stack, so It can be understood as, at the bottom of the stack before the execution JS code is finished forever have a global execution context.

function f1() {
    f2();
    console.log(1);
};

function f2() {
    f3();
    console.log(2);
};

function f3() {
    console.log(3);
};

f1();//3 2 1

We explain the relationship between the stack and by performing the process execution context code above, for ease of understanding, we have the illusion of the execution stack is an array, in the initial execution of the code will create a global execution context onto the stack and, thus process is as follows:

// before the code is executed to create a global execution context 
ECStack = [the GlobalContext];
 // f1 call 
ECStack.push ( 'f1 functionContext' );
 // f1 and calls can not console before f2, f2 finished 1 
ECStack.push ( 'F2 functionContext ' );
 // F2 and calls f3, f3 can not be finished before the console 2 
ECStack.push (' f3 functionContext ' );
 // f3 is finished, the output of the stack 3 and 
ECStack.pop ();
 // F2 performed is completed, and the output of the stack 2 
ECStack.pop ();
 // F1 is finished, the output 1 and the stack 
ECStack.pop ();
 // this case only one execution stack global execution context

So here we explain the rules of the execution stack and store execution context; remember my previous mentioned code is executed before JS engine will make it ready to create the execution context, specifically how to create it, we went on to say.

 ❀ store execution context creation phase

Create a divided execution context creation phase and the implementation phase two stages, the more difficult to understand should be the creation phase, we start with creation phase.

JS execution context creation phase is responsible for three things: to determine this --- lexical creation environment (LexicalEnvironment) --- Create a variable environment (VariableEnvironment)

Here I'll just learn from others translated the pseudo-code data, to represent the creation process:

= ExecutionContext {  
     // determine this value 
    the ThisBinding = < this value> ,
     // Create lexical environment 
    the LexicalEnvironment = {},
     // create lexical environment 
    the VariableEnvironment = {}, 
};

If you have read other articles about the execution context must have read this question, the execution context of the process of creating community should not explain this, the scope of the variable object / active object fishes do , how to say no with other places like this point behind me explain.

1. Determine this

The official call for This Binding, global execution context, this always points to the global object, such as browser environment this point to the window object.

In the context of the implementation of the function, depending on the value of this function is called, if an object is invoked, then this refers to the object. Otherwise, this generally points to the global object window or undefined (strict mode).

Before I write a special article on this blog, it seems that writing is very good, then I will write a new understanding of plain paper.

2. Lexical Environment

Lexical environment containing a variable mapping configuration identifier, the identifier indicates where the name of the variable / function, the variable is a function of the actual object comprises [] type object or a reference to the original value.

Lexical environment consists Environment Record and record the introduction of the external environment of two parts.

Wherein the actual position of the recording for storing environment variables and function declarations, can facilitate executing code corresponding to the assignment. The external environment for the introduction of recording save other external environment can access it, so it comes to this, is not it a little sense of the scope chain?

We first mentioned the global execution context and function execution context, this also led to the lexical environment sub- global lexical environment and function of the lexical environment two kinds.

Global Lexical Environments:

Introducing the external environment record is null, as it is the outermost layer of the environment itself, except that it contains all the attributes of the global object method, and global object (declared by var) user-defined.

Lexical Functions environment:

Contains all the variables in the user-defined function, but also includes a arguments object. Introducing the outside environment may be a function of the lexical environment global environment, the environment may be other functions, in accordance with this comes the actual code.

Borrowing translation of pseudo-code (recorded in the global environment and also different functions, global environmental records in the target environment called record, environmental record function called declarative environment record, say more confused, there are show below):

// global environment 
GlobalExectionContext = {
     // Global Lexical Environment 
    the LexicalEnvironment: {
         // Environment Record 
        EnvironmentRecord: { 
            the Type: "Object" , the object type environment record //
             // identifier binding Here 
        }, 
        Outer: < null > 
    } 
}; 
// function of ambient 
FunctionExectionContext = {
     // function lexical environment 
    the LexicalEnvironment: {
         // environment record 
        EnvironmentRecord: { 
            the type: "the declarative" , // declarative environment record type
            // identifier binding Here 
        }, 
        Outer: <Free Join or outerfunction Environment Reference> 
    } 
};

3. Environment Variables

Environment variables can also say that the lexical environment, it has all the attributes of lexical environment, as has the introduction of environmental records and the external environment. The only difference lies in the ES6 lexical environment variables for storing and let const function declaration statement , and the variable stored in the environment variable var merely declared .

We have to understand them by a bunch 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);

We pseudocode to describe the process of creating the above code execution context:

//全局执行上下文
GlobalExectionContext = {
    // this绑定为全局对象
    ThisBinding: <Global Object>,
    // 词法环境
    LexicalEnvironment: {  
        //环境记录
      EnvironmentRecord: {  
        Type: "Object",  // 对象环境记录
        // 标识符绑定在这里 let const创建的变量a b在这
        a: < uninitialized >,  
        b: < uninitialized >,  
        multiply: < func >  
      }
      // 全局环境外部环境引入为null
      outer: <null>  
    },
  
    VariableEnvironment: {  
      EnvironmentRecord: {  
        Type: "Object",  // 对象环境记录
        // 标识符绑定在这里  var创建的c在这
        c: undefined,  
      }
      // 全局环境外部环境引入为null
      outer: <null>  
    }  
  }

  // 函数执行上下文
  FunctionExectionContext = {
     //由于函数是默认调用 this绑定同样是全局对象
    ThisBinding: <Global Object>,
    // 词法环境
    LexicalEnvironment: {  
      EnvironmentRecord: {  
        Type: "Declarative",  // 声明性环境记录
        // 标识符绑定在这里  arguments对象在这
        Arguments: {0: 20, 1: 30, length: 2},  
      },  
      // 外部环境引入记录为</Global>
      outer: <GlobalLexicalEnvironment>  
    },
  
    VariableEnvironment: {  
      EnvironmentRecord: {  
        Type: "Declarative",  // 声明性环境记录
        // 标识符绑定在这里  var创建的g在这
        g: undefined  
      },  
      // 外部环境引入记录为</Global>
      outer: <GlobalLexicalEnvironment>  
    }  
  }

不知道你有没有发现,在执行上下文创建阶段,函数声明与var声明的变量在创建阶段已经被赋予了一个值,var声明被设置为了undefined,函数被设置为了自身函数,而let  const被设置为未初始化。

现在你总知道变量提升与函数提升是怎么回事了吧,以及为什么let const为什么有暂时性死域,这是因为作用域创建阶段JS引擎对两者初始化赋值不同。

 伍 ❀ 关于变量对象与活动对象

回答前面的问题,为什么别人的博文介绍上下文都是谈作用域,变量对象和活动对象,我这就成了词法环境,变量环境了。

我在阅读相关资料也产生了这个疑问,一番查阅可以确定的是,变量对象与活动对象的概念是ES3提出的老概念,从ES5开始就用词法环境和变量环境替代了,因为更好解释。

在上文中,我们通过介绍词法环境与变量环境解释了为什么var会存在变量提升,为什么let const没有,而通过变量对象与活动对象是很难解释的,由其是在JavaScript在更新中不断在弥补当初设计的坑。

其次,词法环境的概念与变量对象这类概念也是可以对应上的。

我们知道变量对象与活动对象其实都是变量对象,变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。而在函数上下文中,我们用活动对象(activation object, AO)来表示变量对象

那这不正好对应到了全局词法记录与函数词法记录了吗。而且由于ES6新增的let  const不存在变量提升,于是正好有了词法环境与变量环境的概念来解释这个问题。

所以说到这,你也不用为词法环境,变量对象的概念闹冲突了。

我们来总结下上面提到的概念。

 陆 ❀ 总结

1.全局执行上下文一般由浏览器创建,代码执行时就会创建;函数执行上下文只有函数被调用时才会创建,调用多少次函数就会创建多少上下文。

2.调用栈用于存放所有执行上下文,满足FILO规则。

3.执行上下文创建阶段分为绑定this,创建词法环境,变量环境三步,两者区别在于词法环境存放函数声明与const let声明的变量,而变量环境只存储var声明的变量。

4.词法环境主要由环境记录与外部环境引入记录两个部分组成,全局上下文与函数上下文的外部环境引入记录不一样,全局为null,函数为全局环境或者其它函数环境。环境记录也不一样,全局叫对象环境记录,函数叫声明性环境记录。

5.你应该明白了为什么会存在变量提升,函数提升,而let const没有。

6.ES3之前的变量对象与活动对象的概念在ES5之后由词法环境,变量环境来解释,两者概念不冲突,后者理解更为通俗易懂。

不得不说相关文章也是看的我心累,也希望对有缘的你有所帮助,那么到这里,本文结束。

 柒 ❀ 参考

理解JavaScript 中的执行上下文和执行栈

【译】理解 Javascript 执行上下文和执行栈

JavaScript深入之执行上下文栈

JavaScript深入之变量对象

js中的活动对象与变量对象 什么区别?

Guess you like

Origin www.cnblogs.com/echolun/p/11438363.html