Appearance
作用域链
本节目标:理解“作用域链”的核心思路,并能把它用于实际开发或面试表达。
说明:原 OneNote 中有图片引用,但图片未包含在导出目录中;本页保留了可用的文字与代码内容。 变量对象的作用就是保证对变量和函数的正确访问; 而作用域链的用途是保证对变量和函数的有序访问。
作用域链本质上是一个指向变量对象的指针列表(可使用数组表示);它只引用但不实际包含变量对象。最前:作用域链的前端始终都是当前执行上下文的变量对象,如果这个执行上下文属于函数执行上下文,则用活动对象作为变量对象。
最后:全局执行上下文的变量对象(也就是全局对象)始终是作用域链的最后一个对象。
**创建过程**
==作用域链是一个动态的创建过程,通过例子理解一下:==
var number = 1;
compare(5, 10);
function compare(value1, value2) {
inner();
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
function inner() {
var a = 1;
}
}**全局阶段**创建全局上下文:首先在执行全局代码前,先创建全局上下文。
创建全局变量对象:创建全局上下文的第一步是创建全局变量对象创建作用域链:将全局变量对象放入作用域链的顶端,执行上下文中的[[Scope]]属性指向作用域链。如图所示:
此时全局上下文中的[[Scope]]属性可以这样表示
globalContext.[[Scope]] = [
globalContext.VO
];为变量对象所有函数添加[[Scope]]属性:在创建完作用域链后,JavaScript 引擎还执行了最关键的一步,它会为变量对象中的所有函数添加一个[[Scope]]属性,而这个属性的值就是我们刚才介绍的全局上下文中的[[Scope]]属性值。如下,
compare.[[Scope]] = [
globalContext.VO
]==全局上下文创建后,开始执行代码:根据代码动态的修改变量对象中的属性。==
**函数阶段**
如果代码中存在函数的调用:创建函数上下文:在执行compare(5,10)之前,我们会为函数创建对应的执行上下文。
复制[[Scope]]属性:函数上下文首先会复制函数的[[Scope]]属性用来创建作用域链。
创建活动对象:然后用arguments,函数参数,函数内变量声明和函数声明创建活动对象,再将活动对象压入作用域链顶端。
comapre执行上下文复制[[Scope]]属性创建作用域链后可以这样表示
compareContext = {
Scope: compare.[[Scope]],
}
压入活动对象后作用域链如下
checkScopeContext = {
AO: {
...
},
Scope: [AO, [[Scope]]]
}为活动对象所有函数添加[[Scope]]属性:在创建好作用域链后,JavaScript 引擎同样会为变量对象中的所有函数添加一个[[Scope]]属性,而这个属性的值就是当前函数上下文中的[[Scope]]属性值。如所示
inner.[[Scope]] = [
checkScopeContext.AO,
globalContext.VO
];在代码执行阶段会对函数上下文中活动对象属性进行动态修改,因为作用域链是对变量对象的引用,因此我们可以实时地获取变量对象的最新状态,保证对作用域链查询时能够保证变量的准确性。
如果函数内的代码中还有函数调用,将重复一次上面的过程。
函数代码执行完毕后,出栈,销毁变量对象中数据,转交执行权给外部函数执行上下文。
