Open
Description
执行上下文是什么
我们所写的代码,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 执行代码的过程就是创建上下文 —— 推入执行上下文栈 —— 执行 —— 出栈 —— 清空调用栈,结束