iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 5
0
Software Development

跟我一起上課吧:了解 JavaScript 的奇怪部分系列 第 5

Day 5-變數環境、scope chain

variable environment 變數環境

描述變數創造的位置,和在記憶體中和其他變數的關係
簡單來說,就是在問「變數在哪裡」

每個執行環境有自己的變數環境

以上圖例子舉例,每個執行環境都有 myVar 這個變數,而因為每個執行環境都有自己的變數環境,所以每個執行環境的 myVar 其實是不一樣的且不會被影響,這其實是 scope 的概念。

來證明吧!

jsbin

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

scope chain 範圍鏈

先來看一個例子,跟前面例子很像,差別在於 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()

有幾種猜測方向:

  1. 選 A: undefind 的人:因為他在 b() 執行環境中,而 myVar 沒被宣告

  2. 選 B: 2 的人:因為 b() 在 a 函數中被呼叫,或許會吃到 a 函數中的值(?

以上都不是,答案是 1

首先我們來看前面提到的,每個執行環境都有自己的變數環境,在 b() 執行環境中,因為沒有宣告 myVar 所以記體中沒有這個變數,那需要 myVar 時怎麼辦?這時就會到他的「外部環境」去找。

其實每個執行環境在創造的時候,除了全域物件、this 之外,還有一個「外部環境參照(Reference to Outer Environment)」

b() 執行環境來說,他的外部環境參照是全域執行環境,對 a() 執行環境的外部環境參照也是全域執行環境

外部環境參照

為什麼 b() 執行環境的外部環境參照是全域執行環境呢?這是怎麼決定的?

是透過「詞彙環境」決定的。
還記得這個詞嗎?前面有提到過。

詞彙環境就是程式碼所在的實際位置,所以因為 b 函數的程式碼實際位置在「全域環境」,所以他的外部環境參照就是在全域執行環境,a 函數也是如此。

回到 scope chain

剛剛說 b() 因為在自己的執行環境找不到 myVar,所以到它的外部環境去找,假設它的外部環境也沒有,就會再找外部環境的外部環境,直到找到了全域執行環境,全域執行環境是最外層、沒有外部環境了。

範圍(scope)代表我能取用變數的地方,
鏈(chain)是外部參照的連結。

這樣的串連看起來很像鏈子,就稱為範圍鏈(scope chain)

改變詞彙環境看看

如果以上你懂了,那我們再試試一個例子確定你懂了。

我們來試試改變 b() 的詞彙環境,我們把 b 函數移到 a 函數裡,這時 myVar log 出來的值會是多少?

jsbin

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()

答案是多少?

重點整理

  • 每個執行環境有自己的變數環境
  • 每個執行環境在創建時,會建立創建全域物件、this 還有外部參照連結,只有全域執行環境沒有外部參照連結
  • 外部參照連結是根據該執行環境的詞彙環境,也就是該程式碼的實際位置
  • 範圍(scope)代表我能取用變數的地方,鏈(chain)是外部參照的連結。

上一篇
Day4-單執行緒、同步執行、執行堆
下一篇
Day6-scope、let
系列文
跟我一起上課吧:了解 JavaScript 的奇怪部分7
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言