变量生命周期指其从创建到销毁的全过程,核心在于内存分配、使用与回收:基本类型存栈中,引用类型数据存堆中、栈存地址;函数结束栈变量自动释放,堆对象依赖可达性判断是否存活;引擎通过标记-清除算法回收不可达对象。

变量生命周期就是它从出生到消失的全过程,核心是内存怎么来、怎么用、怎么走。它不靠你手动控制,但你得知道引擎怎么想——关键就三点:谁在用它、还能不能找到它、该不该留着它。
变量怎么诞生:栈和堆分工明确
声明变量那一刻,内存就分配好了,位置取决于类型:
- 基本类型(number、string、boolean、null、undefined、symbol、bigint)直接存在栈里,值本身就在那儿;
- 引用类型(对象、数组、函数、DOM 节点等)实际数据存在堆里,栈里只存一个指向它的地址;
- 函数执行完,栈里局部变量自动清掉;堆里的对象不会自动消失,得看有没有人还“记得它”。
变量怎么存活:只看“能不能被找到”
JS 不管你有没有 let 或 const,只认一个标准:可达性。只要能从根对象顺藤摸瓜访问到,它就算在职:
- 根对象包括:全局对象(window/global)、当前执行函数的参数和局部变量、调用栈上的活跃函数、DOM 树根节点;
- 一旦所有引用链断开——比如 obj = null、函数执行完毕且没闭包捕获、事件监听器没解绑——对象就变成“找不到的人”,标记为待回收;
- 闭包是特例:内部函数持续引用外部变量,会让那些本该随函数结束而消失的局部变量继续活在堆里。
变量怎么退场:标记-清除不是实时,但很靠谱
现代引擎(V8、SpiderMonkey 等)主要用标记-清除算法,分两步:
- 标记阶段:从根出发遍历,把所有能到达的对象打上“活跃”标签;
- 清除阶段:扫一遍堆,把没被打标的对象内存全清掉,空出来复用;
- 回收不发生在每行代码后,而是在内存压力上升或空闲时触发,所以有延迟但能处理循环引用——a.ref = b 且 b.ref = a,只要它们都脱离了根链,照样一起被清。
哪些操作容易让变量“赖着不走”
有些写法看着正常,其实悄悄延长了对象寿命:
- 把大对象挂到 window 上(如 window.cache = hugeData),它就一直活到页面关闭;
- 没清理的定时器(setInterval 持有回调,回调又引用外部数据);
- DOM 元素被移除后,监听器还挂在上面没解绑;
- 控制台里无意保留了对大对象的引用(比如在 DevTools 中打印过某对象,又没刷新控制台)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











