作用域鏈 Scope Chain
作用域鏈?zhǔn)且粭l變量對象組成的鏈,與執(zhí)行上下文有關(guān),用于處理標(biāo)識符時進(jìn)行變量查詢。
函數(shù)擁有一個內(nèi)部屬性[[scope]],該屬性由ES3規(guī)范定義,只能被JS引擎讀寫。[[scope]]包含一個函數(shù)被創(chuàng)建的作用域中對象的集合,這個集合就是作用域鏈。

靈魂圖例.png
函數(shù)執(zhí)行時,沒遇到一個變量,都會在作用域鏈中進(jìn)行查找。按順序查AO/VO,遍歷對象中的鍵,尋找同名標(biāo)識符。若該變量對象中無同名標(biāo)識符,則查找下一個VO。如果遍歷完作用域鏈還沒找到,則會拋出 * is not defined 的錯誤。
這就是shadow的原因,當(dāng)在不同一個VO中由同名標(biāo)識符時,會取前一個的值,此時后一個就被shadow了。
作用域鏈在代碼執(zhí)行時只會被with及catch改變。
- with
with語句傳入的對象會被插入作用域鏈的首位。 - catch
catch語句會把捕獲到的異常插入作用域鏈的首位。
閉包 closures
定義
有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)——紅寶書
能夠訪問自由變量(函數(shù)中既非函數(shù)參數(shù)arguments亦非局部變量的變量)的函數(shù)——MDN
當(dāng)閉包被創(chuàng)建時,閉包的[[scope]]屬性被初始化,[[scope]]包含了與執(zhí)行環(huán)境作用域鏈相同的對象的引用。
例如:
var x = 10;
function test(){
console.log(x);
}
(()=>{
var x = 20;
test(); //10
})();
因為[[scope]]時創(chuàng)建執(zhí)行上下文時就創(chuàng)建的,作用域鏈時這個時候確定的,是靜態(tài)詞法鏈。
Function構(gòu)造器創(chuàng)建的函數(shù)[[scope]]只包含全局對象
例如:
var x = 10;
function test(){
var y = 20;
var test1 = Function('console.log(x)');
var test2 = Function('console.log(y)');
test1(); //10
test2(); // Uncaught ReferenceError: y is not defined
}
test();