描述變數創造的位置,和在記憶體中和其他變數的關係
簡單來說,就是在問「變數在哪裡」
每個執行環境有自己的變數環境
以上圖例子舉例,每個執行環境都有 myVar
這個變數,而因為每個執行環境都有自己的變數環境,所以每個執行環境的 myVar
其實是不一樣的且不會被影響,這其實是 scope
的概念。
來證明吧!
function b () {
var myVar;
console.log(myVar)
}
function a () {
var myVar = 2;
console.log(myVar)
b();
}
var myVar = 1;
console.log(myVar)
a()
會得到如下的結果,證明每個變數環境是不會被影響的
// console
1
2
undefind
先來看一個例子,跟前面例子很像,差別在於 b()
函數不宣告變數而是直接 console myVar
,會出現什麼?
A: undefind
B: 2
C: 1
你會選什麼?
function b () {
console.log(myVar) // 直接 console myVar,會是什麼?
}
function a () {
var myVar = 2;
b();
}
var myVar = 1;
a()
有幾種猜測方向:
選 A: undefind 的人:因為他在 b()
執行環境中,而 myVar 沒被宣告
選 B: 2 的人:因為 b()
在 a 函數中被呼叫,或許會吃到 a 函數中的值(?
以上都不是,答案是 1
首先我們來看前面提到的,每個執行環境都有自己的變數環境,在 b()
執行環境中,因為沒有宣告 myVar 所以記體中沒有這個變數,那需要 myVar 時怎麼辦?這時就會到他的「外部環境」去找。
其實每個執行環境在創造的時候,除了全域物件、this 之外,還有一個「外部環境參照(Reference to Outer Environment)」
對 b()
執行環境來說,他的外部環境參照是全域執行環境,對 a()
執行環境的外部環境參照也是全域執行環境
為什麼 b()
執行環境的外部環境參照是全域執行環境呢?這是怎麼決定的?
是透過「詞彙環境」決定的。
還記得這個詞嗎?前面有提到過。
詞彙環境就是程式碼所在的實際位置,所以因為 b 函數的程式碼實際位置在「全域環境」,所以他的外部環境參照就是在全域執行環境,a 函數也是如此。
剛剛說 b()
因為在自己的執行環境找不到 myVar,所以到它的外部環境去找,假設它的外部環境也沒有,就會再找外部環境的外部環境,直到找到了全域執行環境,全域執行環境是最外層、沒有外部環境了。
範圍(scope)代表我能取用變數的地方,
鏈(chain)是外部參照的連結。
這樣的串連看起來很像鏈子,就稱為範圍鏈(scope chain)
如果以上你懂了,那我們再試試一個例子確定你懂了。
我們來試試改變 b()
的詞彙環境,我們把 b 函數移到 a 函數裡,這時 myVar log 出來的值會是多少?
function a () {
function b () {
console.log(myVar) // 會是什麼?
}
var myVar = 2;
b();
}
var myVar = 1;
a()
首先,b 函數已經不在全域環境裡了,全域環境裡只有 a 函數和 myVar 變數。
當執行到 b 函數時,執行堆跟剛才長得一樣,但是此時 b()
執行環境的詞彙環境在 a 函數裡,所以外部環境參照變成 a()
執行環境
所以,在 b()
執行環境找不到 myVar 變數時,會找它的外部環境參照 a()
執行環境裡找,剛好 a()
執行環境找到了,於是最後就會 log 出 2
function a () {
function b () {
console.log(myVar)
}
b();
}
var myVar = 1;
a()
答案是多少?