JavaScript 执行上下文与调用栈详解
发布: (2026年2月7日 GMT+8 21:55)
4 分钟阅读
原文: Dev.to
Source: Dev.to
什么是执行上下文?
执行上下文 是 JavaScript 代码被评估和执行的环境。
可以把它想象成 JavaScript 引擎每次运行代码时创建的一个容器。所有的 JavaScript 代码都在执行上下文中运行。
执行上下文的创建分为两个阶段:
- 内存创建阶段
- 代码执行阶段
内存创建阶段
- 所有变量和函数在任何代码运行之前就已经在内存中分配好。
- 变量的初始值为
undefined。 - 函数以完整的定义形式存储。
- 内存组件将这些条目以键‑值对的形式保存。
代码执行阶段
- 引擎逐行执行代码。
- 变量的值会被更新为代码中实际赋予的值。
- 函数被调用/执行。
- 每一次函数调用都会被压入 调用栈(也称为 执行线程)。
这就是为什么 JavaScript 被描述为 同步单线程 语言:它一次按顺序执行一行代码。
执行上下文的类型
全局执行上下文
- 在 JavaScript 文件首次运行时创建一次。
- 每个脚本只能有一个全局上下文。
函数执行上下文
- 每次调用函数时都会创建一个新的上下文。
- 活动的函数调用越多,存在的上下文就越多。
示例演练
let n = 5;
function multiplyByTwo(x) {
return x * 2;
}
let output1 = multiplyByTwo(n);
let output2 = multiplyByTwo(output1);
-
内存创建阶段
n被存储为undefined。multiplyByTwo被存储为函数对象。
-
代码执行阶段
n被赋值为5。- 调用
multiplyByTwo(n)→ 创建一个新的 函数执行上下文 并压入调用栈。 - 函数返回后,其上下文从栈中弹出,
output1获得返回结果。 - 对
output2的处理过程相同。
调用栈
调用栈 是一种 LIFO(后进先出)数据结构,用于跟踪活动的执行上下文。
操作顺序
- 全局上下文 – 首先创建。
first()– 其上下文被压入栈中。second()– 在first()内部调用,其上下文被压入。third()– 在second()内部调用,其上下文被压入。
当 third() 完成后,它会从栈中弹出,随后是 second(),再是 first(),最后控制权返回全局上下文。
为什么理解执行上下文很重要
- 预测提升(hoisting)行为。
- 调试作用域问题。
- 理解闭包(closures)。
- 防止调用栈溢出。
- 编写更好的异步代码。
结论
执行上下文和调用栈构成了 JavaScript 的基础。一旦掌握它们:
- 闭包 变得合乎逻辑。
- 异步行为 易于理解。
- 调试 更加轻松。