执行上下文
什么是执行上下文
JavaScript引擎在执行代码阶段时,通常是调用函数的时候,就会先做一些准备工作,这个准备工作被称为执行上下文,简称EC,或者也可以叫做执行环境。
执行上下文也是有不同的,有三个类型:
- 全局执行上下文:最基础的执行上下文,一个程序也只会存在一个全局执行上下文,全局上下文会生成一个全局对象,这个对象就是window,并且会将该上下文的中this绑定到该全局对象上。
- 函数执行上下文:当函数被调用时都是产生一个新的上下文对象,不管函数是否是重复调用
- Eval函数执行上下文:执行在
eval
函数内部的代码也会有它属于自己的执行上下文
而this是由上下文中提供的,我们可以将上下文理解为一个object,这样可以方便认知它。
上下文在创建的时候会创建两个环境:
- 词法环境 LexicalEnvironment
- 变量环境 VariableEnvironment
词法环境是比较新的一个环境,用于存放let、const等等一些变量和对应的值,其中就有this
属性。
变量环境是ES6用于区分var声明而提供的环境,里面存放var声明的变量。
let a = 10;
function foo() {
let b = 20;
var d = 40;
console.log(a, b);
}
foo();
这段代码会生成以下上下文环境(伪代码):
//全局执行上下文
GlobalExecutionContext = {
//词法环境
LexicalEnvironment: {
EnvironmentRecord: {
type: 'object',
this: <globalObject>,
a: <uninitialized>,
foo: <function>
},
outer: <null>
},
//变量环境
VariableEnvironment: {
EnvironmentRecord: {
type: 'object',
this: <globalObject>
},
outer: null
},
}
//函数执行上下文
FunctionExecutionContext = {
LexicalEnvironment: {
EnvironmentRecord: {
type: 'declarative',
this: <globalObject>, // 严格模式下为undefined
arguments: {length: 0},
b: <uninitialized>,
},
outer: <GlobalLexicalEnvironment>
},
VariableEnvironment: {
EnvironmentRecord: {
type: 'declarative',
this: <globalObject> // 严格模式下为undefined
d: undefined,
},
outer: <GlobalLexicalEnvironment>
},
}
使用const和let声明的变量在LexicalEnvironment
词法环境中,它的值一开始是uninitialized
,所以虽然在运行时这个变量就存在于环境中了,但是它是一个未初始化的值,所以在没有执行到对应的声明时,提前读取它会触发ReferenceError
报错,这个特性又称之为暂时性死区,而var声明在变量环境中是undefined,所以即时没有被赋值,也是可以正常获取到值,并不会报错。
this会在上下文环境中定义,在下一篇文章,我会讲述定义的规则,这里就不详细说明了。
上下文环境是在运行时创建,在代码使用完就会销毁(除了全局上下文),它就是一个内存中的栈空间,代码在运行时开辟出来,使用完就销毁。虽然这个和作用域很相像,但是不是一个东西,而且是不同生命周期内的产物。
反倒是引擎在创建上下文时,会通过作用域查询对应的变量,然后将需要的内容丢入空间内使用。
其中outer
是用于链接作用域的,本人在这块也很模糊,这个作用域个人估计是链的上下文的词法环境和变量环境,因为值只有在运行时才能确定啊。而闭包也是通过outer
查找到外部变量。
旧的知识
现在百度到的文章,很大一部分都会讲什么AO、VO啥的,其实这个知识是ES3时代的知识,其实没必要去深入学习,但是还是需要了解一下,免得被弄的眼花缭乱。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据