Skip to content

执行上下文(Execution Context)

什么是执行上下文?

代码在运行的时候,执行的环境

不用时期的不同执行上下文

执行上下文在 ES3 中,包含三个部分

  • scope:作用域,也常常被叫做作用域链。

  • variable object:变量对象,用于存储变量的对象。

  • this value:this 值。

JavaScript 深入之执行上下文📚 高性能 JavaScript

在 ES5 中,我们改进了命名方式,把执行上下文最初的三个部分改为下面这个样子

  • lexical environment:词法环境,当获取变量时使用。

  • variable environment:变量环境,当声明变量时使用。

  • this value:this 值。

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

在 ES2018 中,执行上下文又变成了这个样子,this 值被归入 lexical environment,但是增加了不少内容

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

ES2018 最新 【译】理解 Javascript 中的执行上下文和执行栈

执行上下文类型

  • 全局执行上下文

    — 这是默认或者说基础的上下文,任何不在函数内部的代码都在全局上下文中。它会执行两件事:创建一个全局的 window 对象(浏览器的情况下),并且设置 this 的值等于这个全局对象。一个程序中只会有一个全局执行上下文

  • 函数执行上下文

    每当一个函数被调用时, 都会为该函数创建一个新的上下文。每个函数都有它自己的执行上下文,不过是在函数被调用时创建的。函数上下文可以有任意多个。每当一个新的执行上下文被创建,它会按定义的顺序(将在后文讨论)执行一系列步骤。

  • Eval 函数执行上下文

    执行在 eval 函数内部的代码也会有它属于自己的执行上下文,但由于 JavaScript 开发者并不经常使用 eval,所以在这里我不会讨论它。

执行栈

执行栈,也就是在其它编程语言中所说的“调用栈”,是一种拥有 LIFO(后进先出)数据结构的栈,被用来存储代码运行时创建的所有执行上下文

对于每个执行上下文,都有三个重要属性

  • 变量对象 (variable object)
  • 作用域链 (scope chain)
  • this

this

  • 在全局执行上下文中,this 的值指向全局对象。(在浏览器中,this 引用 Window 对象)。
  • 在函数执行上下文中,this 的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 this 会被设置成那个对象,否则 this 的值被设置为全局对象或者 undefined(在严格模式下)。

变量对象

变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。

!!!全局上下文中的变量对象就是全局对象

执行过程 变量对象的过程

  1. 进入执行上下文 当进入执行上下文时,这时候还没有执行代码
    1. 函数的所有形参 (如果是函数上下文)
    2. 函数声明
    3. 变量声明
  2. 代码执行 在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值

总结

  1. 全局上下文的变量对象初始化是全局对象

  2. 函数上下文的变量对象初始化只包括 Arguments 对象

  3. 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值

4.在代码执行阶段,会再次修改变量对象的属性值

变量对象(VO)和活动对象(AO)的区别

未进入执行阶段之前,变量对象(VO)中的属性都不能访问!但是进入执行阶段之后,变量对象(VO)转变为了活动对象(AO),里面的属性都能被访问了,然后开始进行执行阶段的操作。它们其实都是同一个对象,只是处于执行上下文的不同生命周期。

TDZ(暂时性死区)

块级作用域中:使用了 let 或者 const,但在还未定义式前不能被使用

js
if (true) {
  // TDZ开始
  tmp = 'abc' // ReferenceError
  console.log(tmp) // ReferenceError

  let tmp // TDZ结束
  console.log(tmp) // undefined

  tmp = 123
  console.log(tmp) // 123
}

hoisting

var 在执行环境创建阶段就提升到了最顶层,在变量对象被赋值为 undefined

参考文章