JS 預編譯程式碼例項分析

顾平安發表於2024-11-29

瞭解 JavaScript 引擎在執行程式碼過程中所做的一些行為是非常必要的,這有助於我們在遇到莫名其妙的呼叫時,能夠大致定位問題所在。在我學習了預編譯的相關知識,並基於該文章,引用其中的一段程式碼,結合“變數提升”、“函式提升”的小示例,對其進行詳細的分析,算是留作一份筆記鞏固記憶、加深理解。

程式碼

console.log(a)
fn1(1)
var a = 123
console.log(a)

var fn1 = () => {
  console.log(a)
}

function fn1(a) {
  console.log(a)
  var a = 666
  console.log(a)
  function a() {}
  console.log(a)
  var b = function () {}
  console.log(b)
  function c() {}
}

fn1(1)

錯誤的推導會讓你認為上述程式碼的列印如下:

如果你判斷首行報錯,那麼需要了解變數提升
或者你這樣認為
undefined
undefined
666
[Function: a]
[Function: b]
123
undefined
666
[Function: a]
[Function: b]

實際上,上方的程式碼列印如下:

undefined
[Function: a]
666
666
[Function: b]
123
123

詳細分析

1. 建立全域性物件 GO

在全域性執行上下文中,建立全域性物件 GO

2. 載入當前 JS 檔案

載入並解析當前的 JavaScript 檔案。

3. 指令碼語法分析

進行語法分析,確保程式碼沒有語法錯誤。

4. 當前 JS 檔案預編譯

4-1. 查詢變數宣告
GO = {
  a: undefined
}
4-2. 查詢函式宣告(除了函式表示式)
GO = {
  a: undefined,
  fn1: function fn1(a) {}
}

5. 正常執行(執行到函式呼叫前)

console.log(a) // 列印 undefined
fn1(1) // 執行到這裡了,小心,函式也有預編譯,執行前一刻完成

6. 函式預編譯

6-1. 建立活躍物件 AO
AO = {}
6-2. 查詢變數和形參
AO = {
  a: undefined,
  b: undefined
}
6-3. 實參值和形參統一
AO = {
  a: 1,
  b: undefined
}
6-4. 查詢函式(非函式表示式)
AO = {
  a: function a() {},
  b: undefined,
  c: function c() {}
}

7. 正常執行函式(根據 AO)

console.log(a)  // 列印 function a() {}
var a = 666  // a 改變,AO.a = 666
console.log(a)  // 列印 666
function a() {}  // 該宣告已提升過,不會覆蓋
console.log(a)  // 列印 666
var b = function () {}  // b 改變,AO.b = function () {}
console.log(b)  // 列印 function () {}
function c() {}  // 該宣告已提升過,不會覆蓋

8. 接著執行函式外程式碼,執行到下個函式呼叫前

fn1(1) // 已講述,上續
var a = 123  // GO 物件中的 a 改變為 123(undefined > 123)
console.log(a)  // 列印 123

var fn1 = () => {  // fn1 改變,GO.fn1 = () => {...}
  console.log(a)
}

function fn1(a) {  // 該宣告已提升過(函式提升),不會覆蓋
  ...
}

fn1(1)  // 執行到這裡時,預編譯

9. 函式預編譯

9-1. 建立活躍物件 AO
AO = {}
9-2. 查詢變數和形參
AO = {
  a: undefined
}
9-3. 實參值和形參統一
AO = {
  a: 1
}
9-4. 查詢函式(非函式表示式)
AO = {
  a: 1
}

10. 正常執行函式(根據 AO)

console.log(a)  // a 不存在當前函式作用域,往上級查詢,找到 GO.a,列印 123

總結

  • 全域性預編譯:建立 GO 物件,查詢變數宣告和函式宣告。
  • 函式預編譯:建立 AO 物件,查詢變數和形參,實參值和形參統一,查詢函式宣告。
  • 執行階段:按照程式碼順序執行,變數賦值和函式呼叫。

相關文章