Hoisting 稱作「提升」,會將變數宣告
、函式宣告
提升到它們所在作用域的頂部,但要注意賦值
不會被提升。
先來看一段程式碼進入狀況~
console.log(a) // 輸出 undefined
var a = "今天喝拿鐵"
從這個程式碼可以看出,為什麼在a
被宣告之前可以拿得到undefined值(?)
實際上在瀏覽器(編譯器)中是長這樣子 ↓
var a
console.log(a) // undefined
a = "今天喝拿鐵"
有發現var a
像是被提升到最上方了嗎?這就是「提升Hoisting」
因為賦值
不會被提升,所以只有var a
(變數宣告)被拉到這個作用域(Scope)的最上方。
為什麼會說「像是」被提升到最上方?
因為在程式碼在實際上的位置還會一樣的,並不會真的移動到程式碼,當我們說的變數提升或是函式被提升時,實際上是在編譯階段中先將它們放在記憶體中。
有提升(Hoisting)的特性,還是都會強烈建議先宣告完後再使用。
在ES6之後,大部分的開發者已經棄用var
來宣告變數,改為使用let
或const
。
為什麼?
使用let
或const
再宣告之前呼叫就會拋出ReferenceError
,而不是undefined
console.log(drink)
let drink = "明天喝冰美式" // 錯誤:ReferenceError
如果在let
或const
宣告之前呼叫,瀏覽器會報錯誤訊息,而不是undefined
,這個情況就稱之為「暫時性死區(Temporal Dead Zone)」。
如果是使用function
定義則屬於「函式宣告」
先來看看程式碼
qq(5,5) // 想想看這邊會印出什麼?
function qq(a,b){
return a * b
}
公佈正解:qq(5,5)
會印出25
為什麼?我明明是在function
定義完之前呼叫,怎麼不會報錯呢?
原因是「函式提升」與「變數提升」的差別在於,「函式提升」會將函式全部(包括內容)往上提升而且優先權比較高,因此上面的程式碼會輸出function而不是undefined~!
最後來整理出Hoisting的要點
為了避免遇到Hoisting的情況,還是強烈建議先定義好再使用,也可以養成寫程式良好的習慣唷!
參考資料
MDN
我知道你懂 hoisting,可是你了解到多深?