Skip to content

JS 执行上下文 #6

Open
Open
@myLightLin

Description

@myLightLin

执行上下文是什么

我们所写的代码,JS 并不是一句一句执行的,而是一段一段进行分析执行。JS 引擎首先会编译代码,然后创建这段代码的执行上下文信息,将它推到一个调用栈里,就是我们所说的执行上下文栈。而执行上下文分为三种:全局执行上下文函数上下文 还有 eval 上下文

以 ES2018 版本为例,执行上下文包含以下信息:

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

这里面值得一提的就是变量环境和词法环境,我们平时通过 var 声明的一些变量标识符就会存放于变量环境里,而 ES6 引入了块级作用域后,对应 let const 声明的变量,则是存放于词法环境里。通常,函数内部查找一个变量时,首先会从当前执行上下文的词法环境栈顶里开始找,找不到再去变量环境里找,再找不到就继续往上一层的上下文变量对象里去找,这就是我们所说的作用域链的查找。

下面通过一段代码,来分析下执行上下文的创建过程:

var a = 1
function foo() {
  let b = 2
  console.log(b)
}
var c = 3
foo()

JS 引擎编译执行这段代码时,首先把这段代码当做一个整体,创建一个全局上下文,初始化变量对象,变量对象包含的信息如下:

变量环境:a = 1,foo = function() {},c = 3
词法环境:无

然后这个全局上下文就被推入到调用栈,接着执行后,遇到函数 foo,于是又创建函数 foo 的执行上下文,初始化函数的活动对象,里面包含的信息如下:

变量环境:无
词法环境:b = 2

接着将 foo 函数执行上下文推入到调用栈,然后执行 console.log(b) 语句,发现 b 在函数 foo 的执行上下文里词法环境就能找到,于是打印 2。执行完毕后 foo 函数执行上下文出栈,然后是全局执行上下文出栈,这段代码就执行完毕了。

总结

  • JS 引擎在执行一段代码时,需要编译生成信息,这些信息就是执行上下文
  • JS 代码有多种声明方式,比如全局代码,函数代码,所以相对应的有全局上下文,函数上下文,多个执行上下文通过一个 的数据结构来管理
  • JS 执行代码的过程就是创建上下文 —— 推入执行上下文栈 —— 执行 —— 出栈 —— 清空调用栈,结束

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions