作用域鏈
當函數(shù)被執(zhí)行,便進入了自己的執(zhí)行上下文,
該執(zhí)行上下文中的變量若并沒有被找到,
就會往上一層的作用域中去查找。
直到該作用域的頂層(一般為全局環(huán)境中)
JS權威指南中有一句很精辟的描述: ”JavaScript中的函數(shù)運行在它們被定義的作用域里,而不是它們被執(zhí)行的作用域里.”
由上可知,作用域鏈的規(guī)則確定,是函數(shù)在哪里聲明在地方,而非被執(zhí)行的作用域中。
可以將此過程理解為,js引擎在解析js代碼的時候就確定了函數(shù)的作用域鏈規(guī)則,而非是執(zhí)行時產(chǎn)生的執(zhí)行上下文而確定的作用域鏈。
函數(shù)被聲明時
當函數(shù)被聲明的時候,其函數(shù)內部有一個[[scope]]的屬性,里面保存了該父作用域鏈級規(guī)則。
函數(shù)聲明和執(zhí)行的過程
以下為例
var scope = "global scope";
function checkscope(){
var scope2 = 'local scope';
return scope2;
}
checkscope();
- checkscope函數(shù)被創(chuàng)建時,作用域鏈相關規(guī)則被保存到內部屬性[[scope]]中
checkscope.[[scope]] = [
globalContext.VO
];
執(zhí)行checkscope函數(shù),checkscope函數(shù)創(chuàng)建上下文(
checkscopeContext)。checkscopeContext被push進執(zhí)行上下文棧中,以便執(zhí)行代碼。checkscope函數(shù)并不馬上執(zhí)行,而是初始化活動對象,加入形參、函數(shù)聲明、變量聲明,復制作用域鏈并將活動對象壓入 checkscope 作用域鏈頂端
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
},
Scope: checkscope.[[scope]],
}
將活動對象壓入 checkscope 作用域鏈頂端
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: undefined
},
Scope: [AO, [[Scope]]]
}
- 始執(zhí)行函數(shù),隨著函數(shù)的執(zhí)行,修改 AO(變量對象) 的屬性值
checkscopeContext = {
AO: {
arguments: {
length: 0
},
scope2: 'local scope'
},
Scope: [AO, [[Scope]]]
}
- 執(zhí)行完函數(shù),并從執(zhí)行上下文棧中彈出。
作用域和執(zhí)行上下文
- 作用域規(guī)定了函數(shù)內部變量,和內部函數(shù)的可訪問范圍。js沒有塊級作用域,當生命一個函數(shù)的時候,就產(chǎn)生了一個局部作用域。是一套規(guī)則
- 而執(zhí)行上下文是,當函數(shù)在執(zhí)行的時候,不僅僅是作用域和作用域鏈的訪問規(guī)則。而是包括活動變量,形參等等的AO的環(huán)境。