weakmap 通过弱引用键对象避免内存泄漏,而普通 map 或对象因强引用键导致 dom 元素等无法被垃圾回收;其键必须为对象且需校验类型,值仍需注意生命周期以防泄漏。

WeakMap 通过弱引用键对象,让 JavaScript 引用类型(如 DOM 元素、普通对象、组件实例等)在失去所有强引用后能被垃圾回收器自动清理,从而避免内存泄漏。
为什么普通 Map 或对象会引发泄漏
当你用 Map 或普通对象存储引用类型数据时,键会被强引用:只要条目存在,GC 就认为该对象“可达”,即使它已从 DOM 移除或不再使用,也无法释放。
- 例如:
map.set(domEl, { state: true })→ domEl 被 map 持有,remove() 后仍驻留内存 - 挂载属性如
domEl.__cache = data同样构成强引用,污染原生对象 - 全局闭包中长期持有 DOM 引用,也会阻断回收路径
WeakMap 的关键防护机制
WeakMap 的键必须是对象,且是弱引用——它不参与 GC 的可达性判断。只要对象没有其他强引用,GC 就能安全回收它,对应 WeakMap 条目也随之失效。
- 键只能是 Node、Element、Document、Object 等实例,不能是字符串、null、undefined 或 document.querySelector() 返回的 null
- 务必校验:
if (node && node instanceof Node) { wm.set(node, data) } - 动态插入的节点需确保已挂载,否则
getElementById返回 null 会导致 set 报错
典型安全用法示例
给 DOM 元素附加状态,不干扰生命周期:
- 创建单例 WeakMap:
const elementState = new WeakMap() - 封装防护接口:
function setState(el, data) { if (el instanceof Element) elementState.set(el, data) } - 事件中读取:
el.addEventListener('click', () => { const s = elementState.get(el); s.count++ }) - 移除元素后,
el和elementState中对应条目均被自动清理,无需手动 delete 或 MutationObserver
值(value)也要注意生命周期
WeakMap 只保障键的弱引用,不管理 value 的存活。如果 value 是一个被定时器、未注销回调或长周期闭包持有的对象,它仍会造成泄漏。
- 错误做法:把
elementState.get(el)返回的对象又传进setTimeout闭包中长期持有 - 正确做法:value 应尽量轻量(如纯数据对象),避免反向持有 DOM 或形成闭包循环引用
- 若需复杂逻辑,可将 handler 缓存到另一个 WeakMap 中,使 handler 与元素绑定而非捕获元素本身
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











