每個執(zhí)行上下文都有的三個重要的屬性
- 變量對象(Variable object恨豁,VO)
- 作用域鏈(Scope chain)
- this
函數(shù)的作用域在函數(shù)定義的時(shí)候就決定了
當(dāng)函數(shù)創(chuàng)建的時(shí)候爬迟,會保存所有父變量對象到一個內(nèi)部屬性 [[scope]]中橘蜜,也就是說[[scope]] 是所有父變量對象的層級鏈付呕,但是[[scope]] 并不代表完整的作用域鏈
function foo() {
function bar() {
...
}
}
函數(shù)創(chuàng)建時(shí),各自的[[scope]]為:
foo.[[scope]] = [
globalContext.VO
];
bar.[[scope]] = [
fooContext.AO, //函數(shù)內(nèi)部變量只有進(jìn)入函數(shù)執(zhí)行的時(shí)候才會激活(active objecty AO)
globalContext.VO
];
函數(shù)執(zhí)行上下文中作用域鏈和變量對象的創(chuàng)建過程如下:
var scope = "global scope";
function checkscope(){
var scope2 = 'local scope';
return scope2;
}
checkscope();
- checkscope 函數(shù)被創(chuàng)建象颖,保存作用域鏈到 內(nèi)部屬性
[[scope]]
checkscope.[[scope]] = [
globalContext.VO // js一開始執(zhí)行就會將全局上下文壓入執(zhí)行上下文棧
];
- 執(zhí)行 checkscope 函數(shù)姆钉,創(chuàng)建 checkscope 函數(shù)執(zhí)行上下文
checkscopeContext
- 將
checkscopeContext
壓入執(zhí)行上下文棧
ECStack = [
checkscopeContext,
globalContext
];
- checkscope 函數(shù)并不立刻執(zhí)行,開始做準(zhǔn)備工作潮瓶,第一步:復(fù)制函數(shù)[[scope]]屬性創(chuàng)建作用域鏈
checkscopeContext = {
Scope: checkscope.[[scope]],
}
- 第二步:用 arguments 創(chuàng)建活動對象,隨后初始化活動對象筋讨,加入形參、函數(shù)聲明悉罕、變量聲明
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
},
Scope: checkscope.[[scope]],
}
- 第三步:將活動對象壓入 checkscope 作用域鏈頂端
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
},
Scope: [AO, [[Scope]]]
}
- 準(zhǔn)備工作做完类早,開始執(zhí)行函數(shù)嗜逻,隨著函數(shù)的執(zhí)行,修改 AO 的屬性值
如果這個時(shí)候沒有在AO中查找到對應(yīng)的變量栈顷,則沿著Scope: [AO, [[Scope]]]作用域鏈去查找
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: 'local scope'
},
Scope: [AO, [[Scope]]]
}
- 查找到 scope2 的值,返回后函數(shù)執(zhí)行完畢萄凤,函數(shù)上下文從執(zhí)行上下文棧中彈出
ECStack = [
globalContext
];