WeakMap 通过弱引用键避免内存泄漏:键为对象时,GC 可自动回收无强引用的 DOM 节点,无需手动清理;键必须是 Node 实例且需校验,值不被弱引用,需单独管理生命周期;应使用单例模块封装并限制接口。

WeakMap 能避免全局缓存导致的内存泄漏,核心在于它对键的弱引用机制——只要 DOM 元素或对象被移除且无其他强引用,它就会自动从 WeakMap 中消失,不需要手动清理。
WeakMap 的键是弱引用,不阻碍垃圾回收
普通 Map 或对象字面量(如 {})对键是强引用。哪怕 DOM 节点已从页面中 remove(),只要它还作为 Map 的 key 存在,GC 就认为该节点“可达”,无法回收,形成 detached DOM 树堆积。
WeakMap 不同:它不计入引用计数。节点一旦脱离 DOM、变量被覆盖或作用域退出,失去所有强引用后,GC 可立即回收该节点,对应条目也自然失效。
- 不需要监听
MutationObserver或写cleanup()函数 - 不依赖开发者判断“何时该删”,时机由 GC 自动决定
- 适用于动态增删频繁的场景,比如列表项、弹窗、卡片组件
必须确保键是真实存在的 Node 实例
WeakMap 只接受对象(Node 及其子类如 Element、Document)作键,不接受 null、undefined、字符串或数字。常见错误是直接把 document.getElementById('x') 的返回值传给 set(),而它可能为 null。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 校验必不可少:
if (node && node instanceof Node) - 动态插入的节点要等挂载后再存,避免用未就绪的引用
- 不要用 ID 字符串代替节点本身,否则会报
TypeError
值(value)生命周期需与键对齐
WeakMap 只保证键的弱引用,不管理值的生命周期。如果值里保存了对同一节点的强引用(如 { owner: node }),或被定时器、事件回调长期持有,照样会导致泄漏。
- 避免在私有数据中反向持有节点引用
- 不要把
get()返回的对象塞进全局闭包或长周期回调里 - 值本身若含大型数组、闭包或未注销的监听器,仍需单独清理
封装成单例模块并限制接口
全局多个 WeakMap 实例不仅浪费,还会让状态分散、类型失控。应只导出一个模块级实例,并提供带防护的读写方法。
- 统一实例:
const elementState = new WeakMap(); - 安全写入:
function setElementState(node, data) { if (!(node instanceof Node)) return; elementState.set(node, data); } - 避免误传
Window、Array等非节点对象污染存储逻辑

















