javascript执行上下文生命周期分三阶段:创建时确定this、提升变量/函数、构建作用域链;执行时赋值、处理tdz、触发新上下文;销毁需栈中弹出且无引用,闭包会阻止外层上下文回收。

分析一段复杂代码的执行上下文生命周期,关键是还原 JavaScript 引擎在运行时“搭建舞台—开始表演—撤下舞台”的真实过程。不需要死记阶段名,而是顺着函数调用链条,逐层看每个上下文如何被创建、它的 this 和变量环境怎么确定、何时开始执行、又何时退出。
先识别所有执行上下文的触发点
执行上下文只在三类场景中产生:全局代码首次执行、函数被调用、eval 执行(极少)。复杂代码里真正需要关注的是函数调用嵌套链。
- 从最外层函数开始,画出调用栈结构(比如
main()→fetchData()→process()) - 每个函数调用都对应一个新创建的函数执行上下文,注意箭头函数不创建自己的 this,但依然有独立的执行上下文(含词法环境和变量环境)
- 忽略立即执行函数表达式(IIFE)的语法糖表象,把它当作一次普通函数调用来看待
对每个上下文分阶段拆解创建细节
进入某个函数调用时,引擎立刻启动创建阶段——这一步完全静态可推断,不执行任何赋值语句。
-
绑定 this:检查该函数的调用方式(如
obj.method()、func.call(ctx)、普通调用、箭头函数),确定 this 值;严格模式下普通调用的 this 是 undefined - 初始化变量环境:提升 var 声明(初始化为 undefined)、提升 function 声明(完整函数体)、记录形参(未传则为 undefined)
- 构建词法环境与作用域链:当前函数的词法环境指向其外层函数(或全局)的词法环境,形成可向上查找的链;闭包就在此刻埋下伏笔
跟踪执行阶段的关键行为
创建阶段一结束,马上进入执行阶段——这时才真正运行代码行,也是最容易观察到上下文状态变化的环节。
- 遇到
var x = 10:变量环境中的x从 undefined 被赋值为 10 - 遇到
let y = 20:词法环境中的y被初始化并赋值(注意 TDZ) - 遇到
return inner():触发 inner 的执行上下文创建,当前上下文暂停,控制权移交;此时外层上下文仍保留在栈中,未销毁 - 遇到异步操作(如
setTimeout或 Promise 回调):回调函数会在未来某个时刻新建执行上下文,与当前调用栈无关
确认销毁时机,避免闭包误判
执行上下文不是执行完函数就立刻消失。它只在执行栈中彻底弹出且无任何引用保留时才被回收。
- 普通函数返回后,若没返回内部函数、也没被事件监听器/定时器捕获,其上下文很快被销毁
- 如果函数返回了一个闭包(比如返回 inner 函数),那么外层函数的词法环境会被 inner 持有,即使外层已执行完毕,变量对象仍驻留内存
- 可通过 Chrome DevTools 的 Memory 面板录制堆快照,筛选闭包引用,验证哪些变量因上下文未销毁而持续存在
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











