在上一章我們針對什麼是範疇 ,以及兩種不同的範疇做了說明,而如果 JS 在範疇內找不到某變數, 就會向外尋找。在這章節我會針對這個預設行為做比較詳細的說明。
Outline
- 複習一下執行堆疊
- 範疇鍊:攸關語彙環境
複習一下執行堆疊
這邊我直接上一個稍微複雜點的範例:
我們從全域呼叫了 a 函式,產生了 a 執行環境,後又在 a 函式裡面呼叫了 c 函式,最後在裡面才呼叫了 b 函式 ( a → c → b),因此會有一連串的執行環境依序被產生,而行程執行堆疊。把概念套用到我們之前的模型,(你現在應該可以想像了),大概長這樣,:
範疇鍊:攸關語彙環境
在 function 產生的執行環境內一但找不到某個變數,預設會向外部環境尋找看看該變數有沒有在外面被宣告,這裡的「外部環境」是什麼呢?有人可能會很直覺的看向上面的執行堆疊圖,然後說這個外部環境是上一個執行環境的堆疊。
其實並不是這樣,這邊有一個很重要的觀念,也是今天的重點: JavaScript 會根據前面提過的「語彙環境」,也就是程式碼的實際位置(全域 或是 函式內),來決定要往哪裡去尋找這個找不到的變數。
因為 函式 c 在 函式 a 的裡面,因此我們可以說 c函式的外部語彙環境在 a 函式,以此類推,b 函式的外部語彙環境則是全域環境,因此當我們在 b 函式裡面想要呼叫 c 函式內部的變數的時候,理所當然是找不到的(因為 JS 會從 b 函式的執行環境往全域尋找)。 最後附上對應的程式碼圖來驗證上面的說明:
今天的主題其實就是上述的觀念,所以只要能夠了解執行環境與語彙環境的差異,就能知道什麼是「 Scope Chain ( 範疇鍊)」了,當執行環境往外部環境尋找變數,仍然找不到的時候,就會不斷往更外一層的語彙環境去尋找,直到找到這個變數或是找到全域環境為止(如果到全域仍然找不到,就會跳錯誤)。
例如在這個範例裡面的 c 函式,如果想要取用全域變數的時候,會先往外( a 函式)尋找,發現找不到,才又往全域環境尋找(可往上參考語彙環境堆疊圖)。這一連串的查找動作所產生的物理位置的裡外關係(而不是執行環境產生的先後順序),就是 Scope Chain 。