點燈坊

失くすものさえない今が強くなるチャンスよ

ECMAScript 之 Hoisting

Sam Xiao's Avatar 2020-11-23

var 支援 Hoisting, 因此可在執行之後才使用 var 宣告 variable 與 function;但 let 不支援 Hoisting,只能在執行前先宣告好,因為 var 在 JavaScript Engine 的 Creation Phase 已經將 Variable 與 Function 建立完成。

Version

ECMAScript 5

var

console.log(name)
foo()

var name = 'Sam'

function foo() {
  console.log('foo')
}

namefoo() 都在執行後才宣告。

hoisting000

實際執行發現 nameundefined,但 foo() 卻可正常執行,why ?

JavaScript engine 在執行時分兩個時期:

  • Creation Phase
  • Execution Phase

在 creation phase 時,JavaScript engine 會將所有 variable 與 function 都載入 memory,無論 variable 或 function 宣告在實際執行程式之前或之後。

因此 namefoo() 都會先載入 memory。

此時 nameundefinedfoo() 則為完整 function 定義。

因此 console.log(name) 印出 undefinedfoo() 可印出 foo

name 將在 console.log()foo() 執行完後才會指定為 Sam

var name = 'Sam'
console.log(name)

foo()

function foo() {
  console.log('foo')
}

若要正確印出 Sam,則必須在 console.log() 之前執行 var name = 'Sam'

如此 creation phase 雖然 nameundefined,但 execution phase 隨即將 name 指定為 Sam,因此可正常印出 Sam

hoisting001

let

console.log(name)
foo()

let name = 'Sam'

let foo = function() {
  console.log('foo')
}

若由 var 改用 ES6 的 let,則直接 runtime error。

因為 let 並不支援 hoisting,不會在 creation phase 建立 variable 與 function,因此不可在執行後才使用 let 宣告 variable 與 function。

hoisting002

let name = 'Sam'

console.log(name)

let foo = function() {
  console.log('foo')
}

foo()

namefoo() 必須在執行前先使用 let 宣告後方可正常執行。

hoisting003

Conclusion

  • 只有 var 才支援 hoisting,let 沒有支援
  • var 的 hoisting 是因為 variable 與 function 在 creation phase 已經完成配置,其中 variable 為 undefined,function 則包含完整定義,variable 必須在 execution phase 才會定義初始值