WeakMap 通过弱引用键实现私有数据与目标对象生命周期自动同步,避免内存泄漏;键必须为有效对象且需校验,值应为简单状态,须单例封装且不可遍历。

WeakMap 利用弱引用键的机制,让私有数据的生命周期自动与目标对象(如 DOM 节点或类实例)对齐——对象被垃圾回收时,对应条目自动失效,无需手动清理,从根本上切断内存泄漏链。
只对键弱引用,不干涉值的存活
WeakMap 的“弱”仅作用于键(key),比如一个 button 元素。只要页面中没有其他强引用指向它(例如已从 DOM 移除、变量被赋值为 null 或超出作用域),GC 就能立刻回收该节点,WeakMap 中的条目也随之不可访问。
但它的值(value)仍是强引用。如果值里存了定时器回调、未解绑的事件监听器,或者反向持有该节点(如 { owner: button }),这些都会阻止节点回收——这不是 WeakMap 的问题,而是你对值的使用方式出了错。
- 安全做法:值只放简单状态,如 { count: 0, lastClick: 1723554240 }
- 危险操作:把 button.addEventListener(...) 的回调函数直接塞进值里,且不调用 removeEventListener
- 关键原则:值对象必须严格限定在当前上下文,不外泄、不长期驻留
键必须是真实对象,且要校验
WeakMap 只接受对象作键,原始值(字符串 ID、数字、null、undefined)会直接抛出 TypeError。常见错误是把 document.getElementById('x') 不加判断就传进去,而它可能返回 null。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
动态插入的节点也要等挂载完成(node.isConnected === true)再存,否则可能缓存一个尚未就绪的“半成品”引用。
- ✅ 正确写法:if (node && node instanceof Node) { elementData.set(node, data); }
- ❌ 错误写法:elementData.set('#btn-1', data) 或 elementData.set({}, data)
- ⚠️ 注意:window、Array、RegExp 等非 Node 实例对象也不该混入,会污染逻辑
必须单例封装,避免多个 WeakMap 实例
WeakMap 实例要声明在模块顶层,所有函数共用同一个。如果在 class 构造函数里写 this.cache = new WeakMap(),每个实例都持有一份独立映射,不仅浪费内存,还完全失去弱引用意义——GC 无法统一管理分散的引用。
推荐封装成带防护的工具函数,统一入口、统一校验:
- const elementState = new WeakMap();(模块级单例)
- function setElementState(node, data) { if (node instanceof Node) elementState.set(node, data); }
- function getElementState(node) { return node instanceof Node ? elementState.get(node) : undefined; }
不提供遍历能力,这是设计使然
WeakMap 没有 size、没有 keys()、不能 for...of,也不能 clear()。这不是缺陷,而是刻意为之——它不适用于需要统计、批量更新或主动清空的场景。
它的定位很清晰:只为已有对象附加私有元数据,且确保这些数据随对象一同消失。
- ✅ 合适场景:DOM 状态绑定、类私有字段、响应式依赖追踪
- ❌ 替代方案:需要计数或遍历,请用 Map;需要手动控制生命周期,请搭配 delete 显式清理

















