iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0
Modern Web

從零開始的JS學習之路系列 第 13

[Day13] Hoisting

提升(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() {}

let 與 const 的 hoisting


如果我們以為上圖的狀況跟 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


上一篇
[Day12] 從 function 談變數的 Scope
下一篇
[Day14] 傳值或傳址(上)
系列文
從零開始的JS學習之路30

尚未有邦友留言

立即登入留言