预编译
在了解AO
和GO
前,有必要先了解一下预编译
,先来看下面的代码
test() // function test
function test() {
console.log('function test')
}
console.log(name) // undefined
var name = 'ming'
如果有了解过变量提升和函数提升,相信对上面代码的输出结果并不意外
那么为什么会出现这种情况呢?这就涉及到 JavaScript 引擎是怎么解析这两段代码,这也将涉及到预编译
的内容
预编译主要做了什么呢?简单来说其实就是在执行前创建AO
和GO
,初始化变量和函数
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 的执行过程
- 通过调用 test 后创建 AO
AO = {}
- 寻找函数形参和变量声明
AO = {
a: undefined,
b: undefined
}
- 把实参赋值给形参
AO = {
a: undefined -> 1,
b: undefined
}
- 寻找函数声明并赋值函数体
AO = {
a: undefined -> 1 -> function a() {},
b: undefined -> function() {}
}
- 执行函数
- 函数被执行后,由于函数提升和函数优先,第一个 console.log(a) 会打印出
ƒ a() {}
- 然后执行
var a = 2
,此时 AO 内 a 的值就变成了 2,所以接着会打印2
- 由于 function a() {} 在预编译时就已经执行过了,因此便不执行了
- 然后再执行 console.log(a),此时 a 的值仍然是 2
- 将匿名函数赋值给了 b
- 此时执行 console.log(b),b 的值为匿名函数
- 函数被执行后,由于函数提升和函数优先,第一个 console.log(a) 会打印出
GO
全称 Global Object,也称为全局执行期上下文
在全局开始执行时,会创建 GO 对象,跟 AO 类似,直接来看下面代码
console.log(test) // ƒ test() {}
function test() {}
var test = 1
console.log(test) // 1
同样的来逐步分解 GO 的执行过程
- 创建 GO
GO = {}
- 寻找变量声明
GO = {
test: undefined
}
- 寻找函数声明并赋值函数体
GO = {
test: undefined -> function test() {}
}
- 执行代码
- 执行 console.log(test) ,由于函数优先因此会打印出 ƒ test() {}
- function test() {} 已被执行过,因此不再执行
- 把 1 赋值给 test
- 此时打印 test 为 1
总结
- AO 就是在执行函数前进行预编译,称为函数执行期上下文
- GO 就是全局执行前进行预编译,称为全局执行期上下文,也就是 window