【JavaScript 新手筆記】【4】Hoisting

簡單介紹新手入門覺得奇怪的特性 - Hoisting

一、定義

先看看 w3school 上寫的。

Hoisting is JavaScript's default behavior of moving declarations to the top.

意思是

  1. 宣告(declarations)會移動到程式最上面。
  2. 這是 Javascript 默認的行為。

還是有點難懂,看個例子吧。

console.log(car);
var car = "BMW";

以上程式例子,在 C# 或 JAVA 中會有問題,因為宣告在呼叫之後,故無法執行程式。

但是 Javascript 有 Hoisting 特性,「宣告會移動到程式最上面」,所以當 Javascript 創造執行環境時,你的程式碼彷彿會變成以下狀況。

var car;
console.log(car);
car = "BMW";

這就是 Hoisting 特性。宣告(declarations)會自動跑到最上面,故還是可以執行程式,其結果為 undefined,而不是 not defined。

 

二、誰有 Hoisting 特性?

有兩項會自動提升順序至函式最前面:

  1. 所有用 var 宣告的變數
  2. 所有函式宣告式(function declaration)
備註:函式有兩種表示法,分別為函式表示式(function expression)函式宣告式(function declaration),差別在於有沒有使用一個變數去接函式。
        1. 函式表示式(function expression)(無Hoisting特性):
var add = function adddd(a, b) { return a + b; };

        2. 函式宣告式(function declaration)(有Hoisting特性):

function adddd(a, b) { return a + b; };

所以,以下範例解說。

(function () {
    return test();
    var test = function () {
        return 1;
    }
    function test () { return 2; }
})();

這題答案是 2。

因為 Hoisting 特性,var testfunction test () { return 2; } 皆自動提升順序至「區塊(block)」最前面。故此程式碼執行順序如下:

(function () {
    var test;
    function test () { return 2; }
    return test();
    test = function () {
        return 1;
    }
})();

改成這種順序,就一目了然的知道執行結果了。

 

三、Hoisting 特性解說

Hoisting 看起來彷彿真的是 moving declarations to the top。實際上是當 Javascript 在創造(Creation)執行環境時,會去找到你程式中所有宣告變數與函數,然後將這些東西設定到你的記憶體中,並不是 Javascript 真的去搬移你的程式碼。

這表示,當你執行程式前,於創造執行環境時,就將宣告的變數與函數放置於記憶體中某個空間,當執行程式時可以於記憶體中找到被宣告的變數或函數。

但變數的 Hoisting 和 函數的 Hoisting 又有點不同,變數的值並不會一同事先設定於記憶體中,但是函數內的內容會一開始就事先設定於記憶體。

console.log(a); //undefined,因為變數的值並不會Hoisting
b(); //is b,函數內容會連同函數一同Hoisting

var a = "is a";

function b() {
    console.log("is b");
}

變數的值要等到實際執行程式的時候才會知道。

 

四、注意事項

Hoisting 特性好像讓你在哪裡宣告都沒關係,其實這是不正確的。像是上一個範例,其結果是 undefined 而非 is a,因為只有宣告有 Hoisting 特性,設值部分並不會跟的往前移。依賴 Hoisting 絕對不是一個好辦法,永遠事先宣告變數與函數再使用會比較好,這樣才不會讓人搞混。

Hoisting 特性有可能讓程式出現莫名的問題,也為了未來接手維護人員不懂 Hoisting 特性,建議如下:

  1. 使用 letconst 宣告取代 var 宣告。
  2. 使用『函式表示式』取代『函式宣告式』。

或者請養成良好的撰寫風格:

  1. 宣告變數都要放在程式頂端。
  2. 所有函數於使用前定義。

 


 

以上觀念,有任何撰寫不完善或有錯誤,煩請各位指正,謝謝。