變數和函數的宣告會在編譯階段就被放入記憶體,但實際位置和程式碼中完全一樣。
從這段 MDN 對於 hoisting 的說明大概可以了解到,Javascript 在執行程式碼之前會先進行編譯,而在編譯的過程中會將變數宣告以及函式宣告提升 (hoist) 到該 scope 的頂端,但需注意這邊並非實際改動程式碼的位置。
在執行程式碼前,JavaScript 會把函式宣告放進記憶體裡面。這樣在即使在宣告函示之前就先呼叫它,程式碼仍然可以運作
白話文就是我們可以在 function 宣告前就先呼叫它
這樣做的好處是:
使用還沒宣告的變數,會發生錯誤 ReferenceError: a is not defined
使用該變數後才宣告,則會是 undefined
var a
被「提升」到了最上面變數的「宣告」會提升,「賦值」則不會
將 var a = 5
拆成「宣告」跟「賦值」兩個部分,只有變數的宣告 var a
會被提升,但賦值 a = 5
並不會
同理,這邊我們將 var v = 5
拆成 var v
跟 v = 5
,因為宣告會提升、賦值不會,所以上述程式碼可以看成:
答案是 10 而不是 undefined。
雖然我們依照先前提到的將 var v = 3
拆成 var v
與 v = 3
,並且 function 中的變數宣告 var v
被提升了,但因為 function 有參數傳入,按照 function 的 hoisting 規則其實會變成這個樣子:
轉換步驟:
v
並且將值設定為 10var v
則因為步驟 1 已經有 v
這個屬性了,所以忽略不管此時的 VO :
這篇「我知道你懂 hoisting,可是你了解到多深?」講得滿清楚的,以下是我看完文章的簡單筆記:
On entering an execution context, the properties are bound to the variable object in the following order
這邊提到在進入 EC 的時候,會按照底下的執行流程把資訊放到 VO:
undefined
此時該 function 的 VO:
此時該 function 的 VO:
undefined
let 看起來沒有 hoisting:
但實際上卻是:
如果 let 沒有 hoisting,答案應該會是 10,但答案卻是 ReferenceError: Cannot access 'a' before initialization
,代表 let 確實提升了