AO 和 GO 是什么?

74 阅读2分钟

预编译

在了解AOGO前,有必要先了解一下预编译,先来看下面的代码

test() // function test
function test() {
    console.log('function test')
}

console.log(name) // undefined
var name = 'ming'

如果有了解过变量提升和函数提升,相信对上面代码的输出结果并不意外

那么为什么会出现这种情况呢?这就涉及到 JavaScript 引擎是怎么解析这两段代码,这也将涉及到预编译的内容

预编译主要做了什么呢?简单来说其实就是在执行前创建AOGO,初始化变量和函数

AO

全称 Activation Object,活跃对象,也称为函数执行期上下文

AO 具体是怎么运作的呢?来看下面代码

function test(a) {
    console.log(a) // ƒ a() {}
    var a = 2
    console.log(a) // 2
    function a() {}
    console.log(a) // 2
    var b = function() {}
    console.log(b) // ƒ () {}
}
test(1)

根据以上代码,我们来逐步分解来了解 AO 的执行过程

  1. 通过调用 test 后创建 AO
AO = {}
  1. 寻找函数形参和变量声明
AO = {
    a: undefined,
    b: undefined
}
  1. 把实参赋值给形参
AO = {
    a: undefined -> 1,
    b: undefined
}
  1. 寻找函数声明并赋值函数体
AO = {
    a: undefined -> 1 -> function a() {},
    b: undefined -> function() {}
}
  1. 执行函数
    1. 函数被执行后,由于函数提升和函数优先,第一个 console.log(a) 会打印出ƒ a() {}
    2. 然后执行var a = 2,此时 AO 内 a 的值就变成了 2,所以接着会打印2
    3. 由于 function a() {} 在预编译时就已经执行过了,因此便不执行了
    4. 然后再执行 console.log(a),此时 a 的值仍然是 2
    5. 将匿名函数赋值给了 b
    6. 此时执行 console.log(b),b 的值为匿名函数

GO

全称 Global Object,也称为全局执行期上下文

在全局开始执行时,会创建 GO 对象,跟 AO 类似,直接来看下面代码

console.log(test) // ƒ test() {}
function test() {}
var test = 1
console.log(test) // 1

同样的来逐步分解 GO 的执行过程

  1. 创建 GO
GO = {}
  1. 寻找变量声明
GO = {
    test: undefined
}
  1. 寻找函数声明并赋值函数体
GO = {
    test: undefined -> function test() {}
}
  1. 执行代码
    1. 执行 console.log(test) ,由于函数优先因此会打印出 ƒ test() {}
    2. function test() {} 已被执行过,因此不再执行
    3. 把 1 赋值给 test
    4. 此时打印 test 为 1

总结

  • AO 就是在执行函数前进行预编译,称为函数执行期上下文
  • GO 就是全局执行前进行预编译,称为全局执行期上下文,也就是 window