做用域
- 在JavaScript中,咱們能夠將做用域定義爲一套規則,這套規則用來管理引擎如何在當前做用域以及嵌套的子做用域中根據標識符名稱進行變量查找。
這裏的標識符,指的是變量名或者函數名
- JavaScript中只有全局做用域與函數做用域(由於eval咱們平時開發中幾乎不會用到它,這裏不討論)。
- 做用域與執行上下文是徹底不一樣的兩個概念。我知道不少人會混淆他們,可是必定要仔細區分。
JavaScript代碼的整個執行過程,分爲兩個階段,代碼編譯階段與代碼執行階段。編譯階段由編譯器完成,將代碼翻譯成可執行代碼,這個階段做用域規則會肯定。執行階段由引擎完成,主要任務是執行可執行代碼,執行上下文在這個階段建立。
過程
做用域鏈
回顧一下上一篇文章咱們分析的執行上下文的生命週期,以下圖。
咱們知道函數在調用激活時,會開始建立對應的執行上下文,在執行上下文生成的過程當中,變量對象,做用域鏈,以及this的值會分別被肯定。以前一篇文章咱們詳細說明了變量對象,而這裏,咱們將詳細說明做用域鏈。
做用域鏈,是由當前環境與上層環境的一系列變量對象組成,它保證了當前執行環境對符合訪問權限的變量和函數的有序訪問。
爲了幫助你們理解做用域鏈,我咱們先結合一個例子,以及相應的圖示來講明。
var a = 20;
function test() {
var b = a + 10;
function innerTest() {
var c = 10;
return b + c;
}
return innerTest();
}
test();
在上面的例子中,全局,函數test,函數innerTest的執行上下文前後建立。咱們設定他們的變量對象分別爲VO(global),VO(test), VO(innerTest)。而innerTest的做用域鏈,則同時包含了這三個變量對象,因此innerTest的執行上下文可以下表示。
innerTestEC = {
VO: {...}, // 變量對象
scopeChain: [VO(innerTest), VO(test), VO(global)], // 做用域鏈
}
咱們能夠直接用一個數組來表示做用域鏈,數組的第一項scopeChain[0]爲做用域鏈的最前端,而數組的最後一項,爲做用域鏈的最末端,全部的最末端都爲全局變量對象。
不少人會誤解爲當前做用域與上層做用域爲包含關係,但其實並非。以最前端爲起點,最末端爲終點的單方向通道我認爲是更加貼切的形容。如圖。
注意,由於變量對象在執行上下文進入執行階段時,就變成了活動對象,這一點在上一篇文章中已經講過,所以圖中使用了AO來表示。Active Object
是的,做用域鏈是由一系列變量對象組成,咱們能夠在這個單向通道中,查詢變量對象中的標識符,這樣就能夠訪問到上一層做用域中的變量了。
做者:這波能反殺
來源:簡書
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。