執行環境與作用域

執行環境與作用域

JavaScript 是屬於直譯式語言,它會直接透過直譯器來產生代碼,並且運行代碼。

執行的錯誤情境

  • RHS (Right Hand Side) :RHS 取值來自於右側的變數上
  • LHS (Left Hand Side) :LHS 取值來自於左側的變數上
    1
    2
    把「小明」賦予到左側的變數上,就稱為 LHS
    var ming = '小明'
    1
    2
    右邊的值是使用 RHS 取得變數,並且透過 LHS 賦予到左邊的變數
    var min = ming

語法作用域

  • 靜態作用域 :語法作用域又稱為 靜態作用域,所以會在與法解析時就已經確定作用域,而且不會再改變。
  • 動態作用域 :變數的作用域會在函式調用時才決定。

範圍鍊 Scope Chain

JavaScript 是採用 語法作用域 ,所以當函式建立時,作用域就已經被限制在函式範圍內,當在函式內宣告變數時,外層是無法讀取的。

1
2
3
4
5
6
function fn() {
var min = '小明'
console.log(min) // 小明
}
fn()
console.log(min) // min is not defined

也就是說,每個函式的作用域都是獨立的,如果在函式作用域內需要特定變數,但是作用域內並沒有特定變數,此時就會向外查找;
如果向外查找也沒有的話,就會出現 ReferenceError: b is not defined 的錯誤。
而這個向外尋找變數的過程,就叫做 範圍鍊 ,範圍練取決於函式的作用域,與執行環境沒有關係。

1
2
3
4
5
var a = 'a'
function fn1() { console.log(a) }
function fn2() { console.log(b) }
fn1()
fn2()

容易搞混的靜態作用域 ⚡⚡⚡

函式建立時就已經確定作用域,並且 不會改變
因此以下範例來說,當 fn1 建立時就已經確定了 value 的值為 1,就算在 fn2 重新宣告並呼叫,`value = 2` 的有效作用範圍僅止於 fn2 內,並不會影響 fn1 的內容。
1
2
3
4
5
6
7
8
9
10
var value = 1
function fn1() {
console.log(value) // 1
}

function fn2() {
var value = 2
fn1()
}
fn2()

執行環境

建立函式後並執行 (呼叫) 函式,會產生執行環境

舉例來說,如果在函式內宣告一個變數,那變數的作用域就會被限制在函式內,但是如果函式沒有被執行,就不產生執行環境,也就不會有任何變數產生。
也就是說,如果函式反覆被執行,就會不斷產生新的執行環境。

全域也有屬於自己的執行環境,建立時機在網頁一開啟,或是後端 Node.js 一開啟時,執行環境就會被建立。

執行堆疊

  1. 當網頁一開啟時,會先建立全域執行環境
  2. 呼叫 doSomething 時,就會建立 doSomething 的執行環境,並且堆疊在全域執行環境之上
  3. 在 doSomething 內呼叫 sayHi 函式,此時 sayHi 的執行環境就會堆疊在 doSomething

執行環境是一層一層堆疊上去,和函式宣告的時機沒有關聯,而是和函式被呼叫的位置有關

參考資料