JavaScript 提升(Hoisting)


在瞭解提升(Hoisting)之前,先讓我們看看 JavaScript 中變數的有效範圍(Scope)。

變數的有效範圍 (Scope)

在 ES6 之前,JavaScript 變數有效範圍的最小單位是以 function 做分界的。

1
2
3
4
5
6
7
8
9
10
11
var x = 1;

var fn = function(y) {

var x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 1

由於函式 fn() 裡面再次定義了變數 x,所以當我們執行 fn(50) 時,會將 50 作為參數傳入 fn()y,那麼 return x + y 的結果自然就是 100 + 50150 了。

因為「切分變數有效範圍的最小單位是 “function” 」,所以在函式區塊內透過 var 定義的 x 實際上只屬於這個函式。 換句話說,外面的 x 跟 function 內的 x 其實是兩個不同的變數,所以最後一行印出的 x 是 1 而不是 100 。

如果 function 內部沒有 var x 呢?

如果自己的 function 內如果找不到,就會一層層往外找,直到全域變數為止:

範例:

1
2
3
4
5
6
7
8
9
var x = 1;
var fn = function(y) {

// 內部找不到 x 就會到外面找,直到全域變數為止。
// 都沒有就會報錯:ReferenceError: x is not defined
return x + y;
};

console.log(fn(50)); // 51

要注意的是, function 可以讀取外層已經宣告的變數,
但外層拿不到裡面宣告的變數。

沒有 var 宣告的變數會變成全域變數

1
2
3
4
5
6
7
8
9
10
11
var x = 1;

var fn = function(y) {

x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 100

由於在 function 內沒有重新宣告 x 變數,使得 x = 100 跑去變更了外層的同名變數 x

提升 (Hoisting)

一般在寫程式的時候,我們都會定義好變數,然後才去使用它,如果在尚未定義的情況下,直接去使用這個變項,通常都會出現錯誤訊息!

然而,在 javascript 中有一個蠻特別的概念是 hoisting ,指的是在 JavaScript 中,它會把定義的變數移到最前面先執行。

JavaScript 僅提升宣告的部分,而不是初始化。如果在使用該變數後才宣告和初始化,那麼該值將是 undefined。

1
2
3
4
5
6
7
8
9
10
11
12
13
var x = 1;

var fn = function(y) {

console.log(x); // undefined

var x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 1

上面的例子,實際上在瀏覽器 (或者編譯器) 的眼中,是長這樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var x = 1;

var fn = function(y) {
var x;
console.log(x); // undefined


x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 1

除了變數以外,函式也有提升。

透過「函式宣告」方式定義的函式可以在宣告前使用 (函式提升) :

1
2
3
4
5
6
7
fn(2);    // 4


function fn(number) {

return number * number;
}

而透過「函式運算式」定義的函式則是會出現錯誤:

1
2
3
4
5
6
7
fn(2);    // TypeError: square is not a function


var fn = function (number) {

return number * number;
};

與變數提升的差別在於變數提升只有宣告被提升,而函式的提升則是包括內容完全被提升。

參考文獻

  1. https://ithelp.ithome.com.tw/articles/10191549

  2. https://developer.mozilla.org/zh-TW/docs/Glossary/Hoisting

  3. https://pjchender.blogspot.com/2015/12/javascript-hoisting.html