weakmap 可解决 map 因强引用导致的内存泄漏,但仅键为弱引用、值仍强引用,需确保值轻量且不反向引用键;不可用于原始类型键、遍历、统计或通用缓存,应封装为模块单例。

Map 对象内存占用高,核心原因在于它对键是强引用——只要 Map 里存着某个对象(比如 DOM 节点、组件实例),哪怕这个对象在页面中已被移除、代码里也再无其他变量指向它,它依然无法被垃圾回收。WeakMap 能缓解这个问题,但不是“一键替换”就能解决,关键在用法是否得当。
WeakMap 的弱引用只作用于键,不保值
WeakMap 的键是弱引用,意味着:一旦外部所有引用都断开,该键对象会被 GC 回收,整个键值对自动消失。但它的值仍是强引用。如果值里又反向持有键(比如 { owner: node }),或值本身是个大对象、被 setInterval 持有、挂到全局变量上,照样泄漏。
- ✅ 正确做法:值尽量轻量,例如
{ id: 1, dirty: true }、数字、布尔、小对象 - ❌ 错误做法:值存整个 React 组件实例、大数组、或带
node引用的配置对象 - ⚠️ 注意:WeakMap 不能存原始类型作键(如字符串、数字),只能用对象
典型场景:DOM 节点元数据缓存
传统用 Map 缓存 DOM 信息时,节点被 remove() 后仍滞留内存:
const cache = new Map();<br>const el = document.getElementById('box');<br>cache.set(el, { lastUpdated: Date.now() });<br>el.remove(); // el 已从 DOM 移除,但 cache 仍强引用它 → 内存泄漏
换成 WeakMap 就安全:
const cache = new WeakMap();<br>const el = document.getElementById('box');<br>cache.set(el, { lastUpdated: Date.now() });<br>el.remove();<br>el = null; // 外部引用清空后,el 可被 GC,cache 条目自动消失
WeakMap 不适合做通用缓存或状态统计
它没有 size、不能遍历、不支持 clear(),也无法判断当前缓存了多少项。如果你需要:
- 统计已处理节点数量 → 改用普通计数器,别依赖 WeakMap.size(它不存在)
- 批量清理或主动过期 → WeakMap 不支持,需配合定时器 + 外部标记(如用 WeakSet 标记“已处理”,再结合时间戳逻辑)
- 缓存非对象键(如字符串 ID)→ WeakMap 不能用,可考虑 LRU 库 + 手动生命周期管理
必须封装为模块级单例
多个 WeakMap 实例不仅浪费内存,还会让同一类对象的状态分散在不同容器里,难以追踪和维护。推荐写成一个导出的常量:
// cache.js<br>export const nodeMeta = new WeakMap();<br>export const componentState = new WeakMap();
避免在函数内反复创建 WeakMap,否则每个调用都新建容器,起不到集中管理和自动清理的效果。











