代码解析
var a = 2;
function add(b, c) {
return b + c;
}
function addAll(b, c) {
var d = 10;
result = add(b, c);
return a + result + d;
}
addAll(3, 6);
执行过程分析
1. 代码执行前,JavaScript 引擎创建全局执行上下文
在 JavaScript 代码执行前,会创建 全局执行上下文(Global Execution Context,GEC),并将其压入 执行上下文栈(ECS)。
全局执行上下文(GEC)
-
变量对象(VO,Variable Object)
{ a: undefined, add: <function>, addAll: <function>, result: undefined // 因为 result 赋值时没有 `var`,会变成全局变量 }
-
作用域链(Scope Chain)
[VO(Global)]
-
this 指向
- 在浏览器环境中,
this === window
- 在浏览器环境中,
2. 代码开始执行
(1) 解析全局代码
-
var a = 2;
a
赋值为2
。
-
定义函数
add
和addAll
,但不会执行,只是将它们存储在内存中。 -
解析完全局代码后,全局执行上下文 变为:
{ a: 2, add: <function>, addAll: <function>, result: undefined }
3. 执行 addAll(3,6)
当 addAll(3,6)
被调用时:
- 创建
addAll
的执行上下文 addAll
进入执行上下文栈(ECS)
执行上下文栈变化
操作 | 执行上下文栈 |
---|---|
代码开始 | [Global Execution Context] |
调用 addAll(3,6) | [Global Execution Context, addAll Execution Context] |
addAll
的执行上下文
-
变量对象(VO)
{ b: 3, c: 6, d: 10 }
-
作用域链
[VO(addAll), VO(Global)]
-
this
- 指向全局对象(
window
)
- 指向全局对象(
4. 执行 addAll
函数
var d = 10;
- 在
addAll
的执行上下文中,声明d
并赋值10
。
result = add(b, c);
add(3,6)
被调用,此时会创建add
的执行上下文,并压入执行上下文栈。
5. 执行 add(3,6)
- 创建
add
的执行上下文 add
进入执行上下文栈(ECS)
执行上下文栈变化
操作 | 执行上下文栈 |
---|---|
代码开始 | [Global Execution Context] |
调用 addAll(3,6) | [Global Execution Context, addAll Execution Context] |
调用 add(3,6) | [Global Execution Context, addAll Execution Context, add Execution Context] |
add
的执行上下文
-
变量对象(VO)
{ b: 3, c: 6 }
-
作用域链
[VO(add), VO(Global)]
-
this
- 指向全局对象
6. 执行 add
函数
return b + c; // 3 + 6 = 9
add(3,6)
返回9
。add
执行完毕,从执行上下文栈中弹出。
执行上下文栈变化
操作 | 执行上下文栈 |
---|---|
代码开始 | [Global Execution Context] |
调用 addAll(3,6) | [Global Execution Context, addAll Execution Context] |
add 出栈 | [Global Execution Context, addAll Execution Context] |
result = 9;
(result
在全局作用域中)
7. 继续执行 addAll
return a + result + d; // 2 + 9 + 10 = 21
addAll(3,6)
返回21
。addAll
执行完毕,从执行上下文栈中弹出。
执行上下文栈变化
操作 | 执行上下文栈 |
---|---|
代码开始 | [Global Execution Context] |
addAll 出栈 | [Global Execution Context] |
最终返回值 21。
8. 最终的全局作用域
{
a: 2,
add: <function>,
addAll: <function>,
result: 9
}
⚠️ 注意:
result
没有var
声明,所以它会成为全局变量!
总结
-
执行上下文栈(ECS)管理函数的执行过程,遵循“后进先出(LIFO)”原则:
addAll
进入栈 →add
进入栈 →add
出栈 →addAll
出栈 → 全局执行完毕。
-
作用域链决定变量的查找规则:
- 在
addAll
中访问a
,它不在addAll
作用域内,所以会向上查找Global Execution Context
,找到a = 2
。 - 在
addAll
访问result
,它没有var
,默认变为全局变量。
- 在
-
全局变量
result
是隐式创建的,容易污染全局作用域:-
解决方案:使用
var
或let
在addAll
内部声明result
:function addAll(b, c) { var d = 10; var result = add(b, c); // 添加 `var` return a + result + d; }
-
最终返回值
addAll(3,6) // 21
🔹 关键点
- 执行上下文栈 管理函数调用过程。
- 作用域链 决定变量的查找。
- 全局变量污染(
result
未用var
声明)。
这就是 JavaScript 代码的执行过程!🚀