筆記:我知道你懂 hoisting,可是你了解到多深?


Posted by rockyooooooo on 2021-06-30

我知道你懂 hoisting,可是你了解到多深?

在寫程式時,我們會在程式碼的最上面宣告變數,因為變數要宣告了才可以用,這很合理。

但 function 為什麼可以在宣告之前就呼叫呢?這就跟 Hoisting 有關係了。

Hoisting

宣告變數時,會把宣告提升到程式碼的最上面,但是只有宣告會被提升,賦值不會。

console.log(a) // 印出 undefine
var a = 1
console.log(a) // 印出 1

function 也有這樣的特性,所以可以在任何地方宣告 function,都可以存取到 function。

test() // 印出 '123'
function test(){
  console.log('123')
}

順序

直接看例子。

function test() {
  console.log(a) // 印出 [Function: a]
  var a = 'test'
  function a() {
    ...
  }
}

test()

所以 function 優先於變數。

let 及 const 的 Hoisting

let 跟 const 運作方式不太一樣,如果在宣告之前就存取變數,會出現錯誤,但並不代表他們沒有 Hoisting,而且他們在被賦值之前,都不能夠被存取,稱為 TDZ(Temporal Dead Zone)。

Execution Context

※ ES6 的名詞會不一樣,但原理差不多,這邊用 ECMA-262, 3rd edition 來說明

ECMA-262 的規格書寫到:

When control is transferred to ECMAScript executable code, control is entering an execution context. Active execution contexts logically form a stack. The top execution context on this logical stack is the running execution context.

當執行一個可以執行的程式碼(可以想像成一個 function)時,會進入一個 Execution Context(以下簡稱 EC),EC 會層層疊疊形成一個 Stack,最上面的就是目前正在執行的 EC。


圖片來源

最一開始會在 Global EC,每當進入一個 function,就會進入一個新的 EC,最上層就是目前正在執行的 EC,執行結束會把最上層的 EC pop 掉,回到下面那一層,當 Global EC 也執行完,就代表整個程式都結束了。

Varialble Object

每一個 [[Execution Context]](以下簡稱 EC) 都有一個 Variable Object(以下簡稱 VO),在 EC 裡面的每一個 variable 跟 function 都會被存在 VO 裡面當成一個 property。

可以把 VO 簡單的想像成 JavaScript 的 object。

現在有一段程式碼:

function test() {
  var a = 1
}

上面程式碼的 VO 就會像這樣:

VO = {
  a: 1
}

而當宣告一個 function 時,原本的名子如果已經有宣告,新宣告的 function 會覆蓋原本的。

function test() {
  var a = 1
  function a() {
    ...
  }
}
VO = {
  a: [function a]
}

如果是重複宣告一個 variable,則不做任何事。

function test() {
  var a = 1
  var a
}
VO = {
  a: 1
}

參考資料

我知道你懂 hoisting,可是你了解到多深?
ECMA-262, 3rd edition

tags: 筆記, Lidemy-MTR05, Week16

#note #javascript #hoisting







Related Posts

OOP 13 - Dependency Inversion Principle

OOP 13 - Dependency Inversion Principle

MTR04_0803

MTR04_0803

 如何交作業

如何交作業


Comments