簡單介紹新手入門覺得奇怪的特性 - Hoisting
一、定義
先看看 w3school 上寫的。
Hoisting is JavaScript's default behavior of moving declarations to the top.
意思是
- 宣告(declarations)會移動到程式最上面。
- 這是 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 特性?
有兩項會自動提升順序至函式最前面:
- 所有用
var
宣告的變數 - 所有函式宣告式(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 test
與 function 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 特性,建議如下:
- 使用
let
或const
宣告取代var
宣告。 - 使用『函式表示式』取代『函式宣告式』。
或者請養成良好的撰寫風格:
- 宣告變數都要放在程式頂端。
- 所有函數於使用前定義。
以上觀念,有任何撰寫不完善或有錯誤,煩請各位指正,謝謝。