ES6中执行上下文的变动


转发至huozhonglu的博客

先简单说下执行栈是什么:

js执行代码时会创造一个执行上下文(里面包括执行代码所需要的信息),比如下面代码

function foo(){
    let a=1
    return function b(){
        console.log(a)
    }
    b()
}
foo()

调用函数foo时先创建了函数foo的执行上下文,执行到return 的时候又在执行栈里添加了新的函数b的执行上下文,等函数b执行完了之后就把函数b的执行上下文从执行栈里踢出去,再然后foo的执行上下文也踢出去

再详细说一下执行上下文

在es5里它包含了下面三个内容

  • lexical environment:词法环境,当获取变量时使用。
  • variable environment:变量环境,当声明变量时使用。
  • this value:this 值。

但在es6之后是这个样子的

  • lexical environment:词法环境(环境记录+外部词法引用),当获取变量或者 this 值时使用。
  • variable environment:变量环境,当声明变量时使用。
  • code evaluation state:用于恢复代码执行位置。
  • Function:执行的任务是函数时使用,表示正在被执行的函数。
  • ScriptOrModule:执行的任务是脚本或者模块时使用,表示正在被执行的代码。
  • Realm:使用的基础库和内置对象实例。
  • Generator:仅生成器上下文有这个属性,表示当前生成器。

会生成块级作用域

所以:

for(var i=0;i<5;i++){
    setTimeout(()=>{console.log(i)},1000) // i打印出来的都是5
}
for(let i=0;i<5;i++){
    setTimeout(()=>{console.log(i)},1000) // i打印出来的是0,1,2,3,4
}

并且

var、let、const class和function 在执行上下文的创建阶段时,js会在创建阶段执行上下文就将声明的变量、函数和类都创建,
但是var 声明的变量会被初始化为undefined,而 let / const / class 声明的变量不会被初始化 状态为 uninitialized ,并且禁止访问,function 关键字的声明会直接将函数体赋值给对应的函数名。
而且除了var之外,后面几个关键字声明的标识符映射是存放在词法环境里,而var声明的标识符映射是存放在变量环境里

所以:

console.log(c);
let c =1;
//Uncaught ReferenceError: Cannot access 'c' before initialization
//但是var
console.log(d) //undefiend
var d=1;

再谈谈闭包

根据古典闭包定义( closure )包含:

  • 环境部分(环境和标识符列表)
  • 表达式部分
  • 环境(函数的词法环境)
  • 标识符列表( 函数中用到的未声明的变量 )
  • 表达式(函数体)

其实闭包就是一个带有词法环境的函数

声明:高翔的博客|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - ES6中执行上下文的变动


高翔的博客