JavaScript 程式執行原理:hw3:Hoisting


Posted by backas36 on 2021-08-16

hw3:Hoisting

請說明以下程式碼會輸出什麼,以及盡可能詳細地解釋原因。

var a = 1
function fn(){
  console.log(a)
  var a = 5
  console.log(a)
  a++
  var a
  fn2()
  console.log(a)
  function fn2(){
    console.log(a)
    a = 20
    b = 100
  }
}
fn()
console.log(a)
a = 10
console.log(a)
console.log(b)

Answer :

Step1

開始編譯程式 => globalEC 產生並初始化 => 正式執行程式 => global 的 a 賦值為 1 => 遇到 fn() => fnEC 初始化

要特別注意在 fnEC初始化的時候,會遇到 var a =5 ,此時即時 global 已經有 a 了,還是會宣告 a 一次,並且初始化成 undefined,
如果程式改成這樣,

var a = 1 
function fn(){
    console.log(a)
}

那麼 fnEC 就不會再宣告一次,且會印出 1。

那麼因為 fn 裡面有再宣告一次 var a =5,所以再第二次遇到 var a 的時候,會忽略它,因為已經宣告過了。
這是因為 var 允許重複宣告的特性,如果是改用 let 的話,程式就會報錯!

此時 globalEC 與 fnEC 的 scopeChain 如下:

fnEC.scopeChain = [fnEC.AO, fn.[[Scope]] = [fnEC.AO, [globalEC.VO]]

fn2.[[Scope]] = fnEC.scopeChain = [fnEC.AO, fn.[[Scope]]] = [fnEC.AO, [globalEC.VO]]

Step2

執行 fn => console.log(a) //undefined => fn 裡面 的 a 賦值為 5 => console.log(a) // 5 => 遇到 a++ fn 裡面的 a 變成 6 => var a 因為已經宣告過了,當作沒看到 => 遇到 fn2() => fn2的 EC 初始化開始

進入 fn2 初始化 => 沒有遇到變數與 function 的宣告 => 所以初始化階段只有建立 scopeChain => (fn2EC.scopeChain 詳細描述在圖示中)

開始執行 fn2 => console.log(a) // 6 => 遇到 a = 20 ,將 fn 的 a 改成 20 => 遇到 b=100 ,因為在 scopeChain 都找不到 => 在非嚴格模式下會在 global 建立 b 且 b =100 ,如果是嚴格模式下會報錯。

fn2 執行完畢 => 回到 fn 繼續執行 => console.log(a) //20 => fn 執行完畢 => 回到 global => console.log(a) //1 因為目前已經是在 global 中,所以會從 globalEC.scopeChain 找 a ,這時候的 a 為 1 => 再來又將 a 重新賦值為 10 => globalEC.VO 裡面的 a 從 1 變成 10 => console.log(a) // 10 => console.log(b) //100 剛剛在 fn2 時有遇到 b=100 時就已經幫我們在 globalEC 加上 b=100 了,所以 b = 100。

將以上的步驟拼湊起來,我們可以得到這個程式跑出來的結果:

5
6
20
1
10
100

#js #hoisting #程式導師實驗計畫第五期







Related Posts

Vuex 集中式狀態管理

Vuex 集中式狀態管理

Django aggregate and annotate

Django aggregate and annotate

MTR04_0915

MTR04_0915


Comments