在 JavaScript 中,GO(Global Object,全局对象) 和 AO(Activation Object,活动对象) 是与执行上下文密切相关的核心概念。它们分别对应全局作用域和函数作用域的底层实现机制。
一、GO(Global Object,全局对象)
1. 定义
- GO 是全局执行上下文的变量对象,代表全局作用域。
- 在浏览器环境中,GO 是
window
对象;在 Node.js 中是global
对象。 - 所有全局变量、函数声明都会绑定到 GO 上。
2. 创建时机
- 在脚本加载时立即创建,生命周期持续到页面关闭。
- 是 JavaScript 引擎初始化时第一个创建的对象。
3. 内容
- 内置全局属性和方法(如
setTimeout
、Math
、console
等)。 - 开发者声明的全局变量和函数。
var globalVar = "全局变量"; function globalFunc() { /* ... */ } // 等价于 window.globalVar 或 window.globalFunc
4. 生命周期
- 持久存在,直到页面卸载。
二、AO(Activation Object,活动对象)
1. 定义
- AO 是函数执行上下文的变量对象,代表函数作用域。
- 在函数调用时创建,用于存储函数参数、局部变量和内部声明的函数。
2. 创建时机
- 在函数被调用时创建,函数执行完毕后销毁(闭包除外)。
- 每次函数调用都会生成一个新的 AO。
3. 内容
- 函数的形参(Parameters)。
- 函数内部声明的变量(
var
)和函数声明。 arguments
对象(类数组,存储所有实参)。
4. AO 的创建过程
AO 的生成分为两个阶段:
- 进入执行上下文阶段(预解析阶段):
- 创建 AO,初始化形参、函数声明和变量声明。
- 此时变量值为
undefined
,函数声明已完全初始化。
function test(a) { var b = 2; function c() {} var d = function() {}; } test(1); // AO 预解析阶段: AO = { a: 1, // 形参赋值 b: undefined, // 变量声明未赋值 c: reference to function c() {}, // 函数声明已初始化 d: undefined, // 变量声明未赋值 arguments: [...] // 实参列表 };
- 代码执行阶段:
- 按顺序执行代码,为变量赋值。
// 执行阶段: AO = { a: 1, b: 2, c: reference to function c() {}, d: reference to function expression, arguments: [1] };
5. 变量提升(Hoisting)
AO 的预解析阶段解释了变量提升现象:
- 函数声明整体提升,变量声明提升但赋值留在原地。
console.log(a); // undefined(变量提升) var a = 10; func(); // "执行"(函数声明提升) function func() { console.log("执行"); }
三、GO 与 AO 的关系
1. 作用域链(Scope Chain)
- 函数执行时,会创建一个作用域链:
当前 AO → 外层 AO → ... → GO
。 - 变量查找按作用域链逐层向上。
var global = "全局"; function outer() { var outerVar = "外层"; function inner() { var innerVar = "内层"; console.log(innerVar); // 当前 AO console.log(outerVar); // 外层 AO console.log(global); // GO } inner(); } outer();
2. 生命周期对比
GO | AO | |
---|---|---|
创建时机 | 脚本加载时 | 函数调用时 |
销毁时机 | 页面关闭 | 函数执行完毕(闭包除外) |
数量 | 1 个 | 每次函数调用生成新的 AO |
四、示例分析
示例 1:变量提升与 AO
function demo(a) {
console.log(a); // 输出 1(形参已赋值)
console.log(b); // undefined(变量提升)
var b = 2;
console.log(c()); // "函数c"(函数声明提升)
function c() { return "函数c"; }
}
demo(1);
// AO 预解析阶段:
AO = {
a: 1,
b: undefined,
c: reference to function c(),
arguments: [1]
};
示例 2:作用域链
var x = 10;
function foo() {
var y = 20;
function bar() {
var z = 30;
console.log(x + y + z); // 60(从 GO 和外层 AO 查找)
}
bar();
}
foo();
五、注意事项
- 严格模式:
eval
和with
可能动态修改作用域链,但通常不建议使用。 - 块级作用域:
let
和const
引入了块级作用域,其行为与var
不同,不会绑定到 AO/GO,而是存储在词法环境中。 - 闭包:函数返回时,若内部函数引用了外层 AO 的变量,外层 AO 不会被销毁。
理解 GO 和 AO 的机制,是掌握 JavaScript 作用域、闭包、this 绑定等高级主题的基础。