深刻理解javascript系列之执行环境

引言

当javascript代码执行从一个函数进入到另外一个函数的时候,语言在实现上为当前执行函数保存外部的执行环境(变量),在当前函数进行变量标识符查找的时候,查找的规则是首先在当前的执行环境中查找对应的变量,而后逐步从上级的执行环境中查找.这种对变量实现的存储和查找机制就是javascript中的做用链域.下面先从一些js执行环境的基础知识提及,而后从ECMA的规范上理解javascript的执行环境.javascript

基础知识

执行栈

执行栈是存储javascript执行上下文的一种结构,它具备先入先出的特色.javascript在执行的时候会建立全局的执行上下文.在执行到函数代码的时候,会建立新的执行上下文,执行完对应函数的时候,会退出当前的上下文回到以前的执行上下文继续代码的执行.html

声明提高

javascript在建立执行上下文的时候,会对当前执行环境声明的变量进行绑定(初始化存储位置),这个在必定程度上也解决了函数声明的前后顺序问题,下面这段代码是能够正常执行的java

console.log(a);// undefined
var a = 0;// let const与var的区别是在建立对应的以后环境的时候是let const不会为变量绑定初始值,
var会绑定初始值(undefined),引用一个没有初始值的变量会报错
test();
function test() { test2(); }
function test2() { console.log(1); }复制代码

从ECMA规范理解js执行环境

在javascript进入到函数的执行代码的时候,会建立新的执行上下文,将当前的上下文推入执行栈进行代码的执行.下面先简单的理解执行上下文的基本组件:bash

Execution Contexts = {  
  code evaluation state // 代码执行的状态 用户代码的执行暂停和恢复
  Realm // realm是对javascript执行边界的一些限制
  LexicalEnvironment:{    
    this  // 会进行this的bind  理解this是当前函数的caller
    Environment Record  // 用于初始化和存储当前上下文声明的函数声明,变量 
    outer LexicalEnvironment  // 用于从外部的做用域查找标识符(做用域链)  } 
    VariableEnvironment: {} // VariableEnvironment和LexicalEnvironment
   是类似的概念下面会单独进行讲解
}复制代码

this

this是指调用函数的caller.在进入函数执行的时候会建立新的执行上下文而且对this进行绑定(箭头函数使用的是Lexical this,即这个函数被建立时的this就是函数内部的this).闭包

如何肯定this

const obj = {  
  name: 100, 
  test: function() {    console.log(this.name);  }
};
obj.test(); // 100
const obj2 = {  
    name: 200,
    test: () => {    
     console.log(this.name);  // 这段代码的执行环境是全局的环境
    因此箭头函数中this的指向是window  
    }
}
obj2.test(); // undefined 复制代码

上面的代码块中obj是一个引用类型,在ECMA规范中有引用类型的定义,能够理解成下面的形式app

Reference {  
  the base value component // 引用类型的值 对于上面的例子来讲就是obj自己
  the referenced name component // 引用类型的名字  
                      // the Boolean-valued strict reference flag
} 复制代码

在执行上下文中确认this的指向可使用以下的规则: ecmascript


理解VariableEnvironment和LexicalEnvironment

VariableEnvironment是建立执行上下文的时候进行变量的初始化绑定和存储,LexicalEnvironment(LexicalEnvironment在进行变量初始化后会复制一份VariableEnvironment)主要用于在代码执行阶段对标识符的解析而且随着代码执行(例如产生with语句)会建立新的LexicalEnvironment到当前的LexicalEnvironment以前.能够经过下面的例子来加深对上面例子的理解:
function test() {      var a = 10      var obj = {a:20}      with(obj) {        var test2 = function() {          console.log(a)        }        function test3() {          console.log(a)        }      }      return {test2,test3}    }    var hah = test()    hah.test2() //log 20    hah.test3()//log 20 复制代码

理解闭包

当前的函数存在对外部做用域变量的访问会造成闭包.闭包保存的是生成闭包时候的执行上下文的LexicalEnvironment. (Closure is when a function remembers and accesses variables from outside of its own scope, even when that function is executed in a different scope.)ide

参考

VariableEnvironment和LexicalEnvironment的区别函数

lexical-environments-ecmascript-implementationui

ECMAScript2017

how-to-understand-js-realms

相关文章
相关标签/搜索