JavaScript执行上下文栈(ECS)遵循LIFO原则:全局上下文最先入栈且始终存在;函数调用时新建上下文压栈,返回时立即弹出;异步回调以新上下文压栈,递归过深会触发RangeError。

JavaScript 执行上下文栈(Execution Context Stack,简称 ECS)是 JS 引擎管理函数调用和代码执行顺序的核心机制。它遵循“后进先出”(LIFO)原则,全局上下文最先入栈,函数调用时新建上下文压入栈顶,函数执行完毕后立即弹出。
全局执行上下文入栈:脚本启动时自动创建
当 JS 文件开始执行(或浏览器加载 script 标签),引擎会创建并压入一个全局执行上下文(Global Execution Context)。这是栈底唯一且始终存在的上下文,包含全局变量、this 指向(浏览器中为 window)、以及所有未在函数内声明的函数声明。
- 该上下文在页面卸载前不会被弹出
- var 声明和 function 声明会被提升(hoisted),但 let/const 不参与变量提升,仅进入“暂时性死区”
- 全局上下文的 this 绑定取决于执行环境(严格模式下为 undefined,非严格模式下为 globalThis/window)
函数调用触发新上下文压栈
每次调用函数(包括具名函数、匿名函数、箭头函数——但注意:箭头函数不创建自己的 this 和 arguments,仍会创建执行上下文),JS 引擎都会做三件事:创建执行上下文 → 初始化词法环境与变量环境 → 将其压入执行上下文栈顶部。
- 压栈发生在“进入函数体之前”,即调用表达式求值完成、控制权移交函数内部的瞬间
- 每个函数上下文都包含自己的作用域链、this 绑定、arguments 对象(非箭头函数)、以及独立的变量环境
- 嵌套调用形成栈链:foo() → bar() → baz(),栈从底到顶为 [global, foo, bar, baz]
函数返回时上下文立即弹出
当函数执行到 return 语句(显式或隐式,如末尾无 return 也视为 return undefined)、或自然执行到结尾,当前执行上下文就会从栈顶弹出,控制权交还给前一个上下文。
立即学习“Java免费学习笔记(深入)”;
- 弹出后,该上下文内的变量环境、词法环境等内存标记为可回收(若无闭包引用)
- 如果函数内部有 setTimeout、Promise.then 等异步操作,回调函数会在任务队列就绪后,以新执行上下文形式重新压栈(不是复用原上下文)
- 递归调用会导致栈深度增加,超过引擎限制(如 Chrome 约 10000 层)将抛出 RangeError: Maximum call stack size exceeded
调试技巧:通过 console.trace() 观察栈状态
在关键位置插入 console.trace() 可打印当前执行上下文栈快照,直观看到函数调用链和嵌套层级。
- 输出格式类似: (anonymous) @ script.js:5 → foo @ script.js:2 → global code
- 配合浏览器 DevTools 的 “Sources” 面板断点,可逐帧查看栈帧(Call Stack)变化
- 注意:async/await 函数的 await 暂停不导致上下文弹出,而是保存当前上下文状态,后续 resume 时恢复执行(仍属同一上下文)










