為了理解函式提升,讓我們從以下程式碼開啟我們的學習之旅:
1 2 |
console.log(foo); var foo = 9; |
應該輸出什麼呢?
在任何其他程式語言中,這裡的輸出將會是reference error。但是,在JavaScript中,你將得到undefined作為輸出。為什麼?因為JavaScript會提升變數到執行上下文的頂部。執行上下文可以是宣告變數的函式,也可以是宣告變數的JavaScript檔案。所以,讓我們用函式重寫上面的程式碼片段:
1 2 3 4 5 |
function abc() { console.log(foo); var foo = 9; } abc(); |
這裡,變數“foo”提升到函式abc執行上下文的頂部;這意味著你可以在宣告之前訪問foo。簡而言之,無論何時你宣告一個變數,JavaScript直譯器都可以將其分成兩個語句:
- 宣告一個變數。
- 賦值。
變數的宣告位於執行上下文的頂部,而賦值發生在建立變數的位置。所以上面的程式碼片段被分解成兩個語句,如下圖所示:
變數foo被提升到函式abc的執行上下文的頂部,因此當你在宣告之前使用它時,你會得到“undefined”作為輸出。
請記住,使用let語句宣告的變數不會被提升到執行上下文的頂部。
現在你知道JavaScript中的變數是如何被提升的了,接下來讓我們來探討JavaScript中的函式提升。在JavaScript中,可以通過兩種方式來建立函式:
- 作為宣告而建立的函式。
- 作為表示式而建立的函式。
作為宣告或語句建立的函式作為一個整體提升到執行上下文的頂部。但是,作為表示式建立的函式會像變數一樣提升。
為了說明這一點,讓我們建立一個作為語句的函式:
1 2 3 4 |
foo(); function foo() { console.log("hello"); } |
在上面的程式碼中,如果你在函式建立之前使用函式,那麼你會得到hello的輸出。發生這種情況的原因是,作為語句建立的函式會當作一個整體被提升到執行上下文的頂部。
無論何時建立作為語句的函式,都可以在函式建立之前使用該函式。因此,如果你在第5行建立作為語句的函式,那麼你可以在第1-4行中使用該函式,因為函式語句會隨函式主體一起提升到執行上下文的頂部。
函式語句會隨函式主體一起提升到執行上下文的頂部。
函式表示式會像一個變數一樣被提升到執行上下文的頂部。請看下面的程式碼:
1 2 3 4 |
foo(); var foo = function () { console.log("hello"); } |
你正在程式碼中建立函式foo作為表示式,所以JavaScript會像普通變數一樣提升它。 JavaScript會像下圖所示那樣處理上面的程式碼:
正如你在上面的圖片中看到的那樣,foo在執行上下文的頂部被宣告為一個變數,然而,在變數foo中的函式賦值發生在第6行,也就是建立作為表示式函式的地方。所以,當你嘗試執行上面的程式碼時,你會得到錯誤undefined is not a function,如下圖所示:
因此,你不能在函式表示式被建立之前使用函式表示式,因為只有函式宣告會提升到頂部。
綜上所述:
- 函式語句隨函式主體一起被提升到執行上下文的頂部。你可以在函式建立之前使用作為語句建立的函式。
- 函式表示式在建立之前不能使用。只有宣告部分會被提升,賦值發生在建立函式的那一行。
在“輕鬆學習JavaScript”系列的下一篇文章中,我們將介紹JavaScript中更為重要的概念,敬請期待。