未命名的全局变量会引发内存泄漏,因其绕过作用域直接挂载到window上,始终可达,垃圾回收器无法释放其所引用的大对象;常见于漏写let/const、this指向window及错误上下文绑定等场景。

未命名的全局变量会悄悄霸占内存,核心原因在于:它绕过了作用域控制,直接挂载到 window(浏览器环境)上,而全局对象上的属性不会被垃圾回收器(GC)自动清理——只要页面没刷新或关闭,它们就一直驻留。
为什么它“不知不觉”?
因为写法看起来毫无异常,开发者根本意识不到自己创建了全局变量:
-
漏写 var/let/const:比如在函数里写
count = 1000,JS 自动解释为window.count = 1000; -
this 指向 window:普通函数调用时
this默认是全局对象,function init() { this.data = new Array(100000) }就等同于window.data = [...]; -
错误的上下文绑定:事件回调、定时器中未正确绑定
this,也可能意外把大对象挂到全局。
它怎么“霸占”内存?
关键不是变量本身,而是它引用的内容:
- 如果赋值的是一个大型数组、长字符串、DOM 节点或闭包,这些数据结构会持续保留在内存中;
- GC 的 mark-and-sweep 算法从 root(如 window)出发遍历可达对象,而
window.xxx永远可达,所以它引用的所有东西都“活”着; - 多次调用后不断叠加(比如
cache = {...}被反复赋值),旧数据没被覆盖或清空,内存只增不减。
怎么发现和避免?
不用等崩溃,几个简单动作就能提前拦截:
- 所有 JS 文件顶部加
"use strict"—— 此时漏声明变量会直接报错,强制你写let count = 1000; - Chrome DevTools → Memory 面板 → 拍摄 Heap Snapshot,筛选
Detached DOM tree或搜索window下异常大的属性; - 对确实需要的全局缓存(如配置、状态),用完后主动置为
null或重新赋值,切断引用链; - 用 ESLint 规则
no-implicit-globals和no-unused-vars在编码阶段拦截。
本质上,这不是 JS 的缺陷,而是开发者无意中把“临时变量”变成了“永久居民”。只要守住作用域边界,内存就不会被悄悄圈地。

















