Javascript 中的 Hoisting 與 undefined

什麼是 Hoisting ?

JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their scope, prior to execution of the code. —— MDN

JavaScript 是一個由上往下執行的程式語言。依照 MDN 文件的說明, Hoisting 是直譯器在處理我們的程式碼時,會將 function、variables 或 class 的宣告移到程式最上方處理。但其實它的運作原理不是「物理上」的移到最上方,而是在執行環境的創建階段先預留了記憶體的位置。

在介紹 JavaScript 執行環境 的文章中有介紹執行環境的創建階段(Creation Phase),而 Hoisting 就是在創建階段發生的事情。在程式開始被執行以前,被宣告的函式與變數就已經預留了記憶體中的位置。

在這個預留的位置中,變數僅保留儲存值的位置;函式則是會將 {} 內的程式碼一併存入記憶體,這也是為什麼 JavaScript 的 function 不管在程式中的哪個位置宣告,都可以正常讀取不影響執行,因為它在程式正式開始執行前就已經存在記憶體中等待調用了。

1
2
3
4
5
6
7
8
9
10
11
12
// 範例一
var a = 'Hello world.'
console.log(a)
b()

function b() {
console.log('Called b!')
}

// 輸出結果
'Hello world.'
'Called b!'

undefined

先來看兩個範例。

  • 範例一:
    1
    2
    3
    4
    console.log(a)

    // 輸出結果
    Uncaught ReferenceError: a is not defined
  • 範例二:
    1
    2
    3
    4
    5
    console.log(a)
    var a = 'Hello world.'

    // 輸出結果
    undefined

從範例一可以看到如果沒有經過「宣告」,在記憶體中這個變數還不存在,所以會得到 Uncaught ReferenceError ,也就是無法在記憶體中找到儲存這個變數的位置。而範例二中的變數 a 經過 Hoisting 先行保留記憶體位置,所以回傳的結果呈現 undefined

undefined 是什麼?

undefined 是 JavaScript 中的一種「值」。它代表的是: 記憶體中已經有預留位置來儲存變數的值,但變數「賦值」的這個動作尚未完成。

為什麼會發生 undefined ?

1
2
var a               // 變數宣告
a = 'Hello world.' // 變數賦值

一個變數的使用會經過「宣告」和「賦值」兩個步驟。在前面 Hoisting 的說明中可以看到,創建階段只是幫被宣告的變數預留記憶體的位置來儲存值。而「賦值」這件事要等到程式碼被執行到賦值那一行的時候才會完成。所以在程式碼被執行到賦值那一行之前,JavaScript 會把變數的值都預設為 undefined

參考資料

文章內容如有錯誤,歡迎留言討論!


本 Blog 上的所有文章除特别聲明外,均採用 CC BY-SA 4.0 協議 ,轉載請註明出處!