[JS Behind The Scene] 從簡單例子了解 hoisting 的運作機制


Posted by Powerfultraveling 's Blog on 2021-08-21

前言

這篇文章是第十六周的功課,藉由解釋以下程式碼的運作來了解 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)

回答

這一題一樣 cosplay JS engine 跑一次!

Execution Context

engine 進入 global execution context(下稱EC)

產生了一個 varaiable object(下稱VO),裡面紀錄這個 variables 以及 function。

global:{
  VO:{
    a: undefined,
    fn: function,
  }
  scopechain: {
    global.VO
  }
}

fn() 被呼叫執行,進入 fn() 的 EC

產生了一個 fn 的 EC 並在裡面建立 fn() 的 VO 以及 scope chain。

fn:{
  VO:{
    a: undefined,
    fn2: function
  }
  scope chain:{
    自己的 scope: fn.VO,
    global 的 scopechain: global.scopechain = global.VO
  }
}

global:{
  VO:{
    a: undefined,
    fn: function,
  }
  scopechain: {
    global.VO
  }
}

fn2() 被呼叫,進入 fn2 的 EC

fn2:{
  VO:{
  }
  scopechain:{
    自己的 scope: fn2.VO,
    fn 的 scopechain: fn.scopechain = fn.scope + gloal.scope
  }
}

fn:{
  VO:{
    a: undefined,
    fn2: function
  }
  scope chain:{
    自己的 scope: fn.VO,
    global 的 scopechain: global.scopechain = global.VO
  }
}

global:{
  VO:{
    a: undefined,
    fn: function,
  }
  scopechain: {
    global.VO
  }
}

開始執行囉!

  1. 定義變數 a 為 1。
  2. 呼叫 fn()。
  3. 開始跑 fn()。
  4. 印出 a
  5. fn() 裡面雖有 a,但因為是在之後才宣告,目前 只有被 hoisting 進去 VO 裡,值仍然是 undefined, 所以第一個會印出 undefined
  6. 定義變數 a 為 5,VO 裡的 a 變為 5。
  7. 印出 a,這次 a 的值為 5,所以印出 5
  8. 執行 a++,所以 a 變為 6。
  9. 宣告 a ,但 a 在前面早被宣告了,所以這邊的操作無效直接跳過。
  10. 呼叫 fn2()。
  11. 印出 a,fn2() 的 VO 裡沒有 a,所以沿著 scopechain 往上找,在 fn() 裡找到變為 6 的 a,所以印出 6
  12. a 的值改為 20,但 fn2() 裡沒有 a,所以一樣沿著 scopechain 往上找,在 fn() 裡找到變為 6 的 a,改變成 20。
  13. b 的值改為 100,但是沿著 scopechain 往上找,發現根本沒有任何 EC 裡有宣告過 b,所以 b 直接變成值為 100 的全域變數,換言之,在 global 裡的 VO 加上變數 b,且值為 100。
  14. 印出 a 值,此時的 a 值已經被改為 20,所以印出20
  15. 印出 a 值,因為已經回到 global 的 EC 裡,所以在 fn() 裡面一大塊裡對 a 的操作已經無關,只需要檢查 a 在 global 的 VO 裡的值,得出答案為 1,所以印出 1
  16. a 的值改為 10。
  17. 印出 a,10
  18. 印出 b, 100

對答案


#hoisting #variable-object #execution-context







Related Posts

Lidemy 綜合能力測驗破關&心得

Lidemy 綜合能力測驗破關&心得

Thompson Sampling on Searching Engine

Thompson Sampling on Searching Engine

Secure Apache Using Certbot with Let's Encrypt on Ubuntu 20.04

Secure Apache Using Certbot with Let's Encrypt on Ubuntu 20.04


Comments