提升(Hoisting) 在 JavaScript 裡指的是在執行代碼之前,直譯器(interpreter)把變數及函式的宣告先分配到記憶體裡的現象,實際上在程式碼裡的位置還是一樣,但看起來像是把變數及函式的宣告移到程式頂端,故稱為 Hoisting。而提升只是方便解釋這個現象,他背後運作的原理跟移動程式碼沒有關係。
若未宣告 a 變數,就 console.log(a) 會印出什麼?會直接報錯,對吧。
如果在下面加了一行宣告,那情況就不同了,
console.log(a); // 回傳 undefined
var a = 5; 宣告在後面
咦?為什麼?程式是一行一行讀取的,a 未宣告情況應該要跟上面一樣報錯吧?這就是 Hoisting 的基本現象。
可以觀察到,一般正常宣告變數後,console.log 會印出他的值,而 Hoisting 後顯示的是 undefined,原因是 Hoisting 只會對宣告做提升,賦值不會。我們可以把它「想像」成下面這個情況
var a // 宣告被 hoisting
console.log(a); // 回傳 undefined
a = 5; // 而賦值沒有被 hoisting
把一樣的情況放在函式的宣告,雖然沒有讀取到 c 的賦值,但外面 foo(13) 的呼叫傳值進來,產生出來的結果。
function foo(c) {
console.log(c); // 13
var c = 2;
}
foo(13);
所以除了變數的宣告外,函式的的宣告也會被 hosting,而且優先權比變數還高,證明如下例:
console.log(d); // [function: d]
var d = 20;
function d() {}
如果我們以為上圖的狀況跟 var 不同,就以為 let 跟 const 沒有hoisting 那就錯了,來看看它們到底有沒有 hoisting 的狀況(因結果差不多用 let 舉例):
var a = 10;
function test(){
console.log(a); // Cannot access 'a' before initialization
let a = 33;
}
test()
若 let 沒有 Hoisting 那函式應該會往外找到 var a = 10,但結果是報錯 Cannot access 'a' before initialization,回應並沒有找到 a 的初始化,代表 let(與 const) 存在 Hoisting。
008 天重新認識 JavaScript
Huli 我知道你懂 hoisting,可是你了解到多深?
你不知道 Combo : 前菜 Hoisting