weakmap 必须用于 dom 节点与响应式数据映射,因其键为弱引用对象,可避免内存泄漏;而 map 的强引用会阻止节点回收。

WeakMap 在框架源码中常用于建立 DOM 节点与响应式数据(如依赖收集对象、更新函数、组件实例等)之间的弱引用映射,核心目的是避免内存泄漏——DOM 节点被移除时,相关数据能被自动回收。
为什么必须用 WeakMap 而不是 Map?
DOM 节点是原生对象,无法作为普通 JS 对象的属性键(除非转成字符串 ID,但会丢失唯一性和语义)。而 WeakMap 允许以任意对象(包括 DOM 节点)为键,且该引用是弱引用:只要节点从 DOM 树中被移除、且无其他强引用,即使 WeakMap 里还存着它,GC 仍可回收该节点及其关联值。
- Map 的键是强引用 → 会阻止节点被回收 → 长期留存导致内存泄漏
- WeakMap 的键不阻止 GC → 安全、零手动清理
- WeakMap 不支持遍历和 size 属性 → 天然适合“隐藏元数据”场景
典型框架中的使用模式(如 Vue / Solid / 自研响应式库)
以 Vue 3 的依赖追踪和模板更新为例,编译后的渲染函数在挂载时,会对每个响应式绑定的 DOM 元素(如 v-model 输入框、v-if 容器)建立与副作用函数(effect)或依赖对象(dep)的映射:
- 键(key):具体的 DOM 元素(
el),例如<input>或<div> <li>值(value):一个对象,包含 <code>effects: Set<reactiveeffect></reactiveeffect>、cleanup: () => void、甚至instance: ComponentPublicInstance - 后续触发更新时,通过
weakMap.get(el)快速拿到对应 effect 并重运行 - 仅限对象键:WeakMap 的 key 必须是对象(DOM 节点符合),不能是字符串、number 或 null
-
无法枚举/调试:开发者工具中看不到 WeakMap 内容,需靠
console.log(weakMap.get(el))单点验证 - 不要混用 document fragment:临时 fragment 中的节点若未插入文档,也可能被 GC,需确保生命周期对齐
- SSR 场景不适用:服务端无 DOM,WeakMap 无法存储真实节点,通常 SSR 侧跳过此层或降级为 Map + 手动管理
类似地,SolidJS 使用 WeakMap<element dispose:> void }></element> 管理事件监听器和计算资源的自动清理;Svelte 的 runtime 也用 WeakMap 存储 element → template context 映射。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
实际代码片段示意(简化版)
以下是一个精简但真实可用的模式:
const elementToReactiveMap = new WeakMap();
<p>function bindElement(el, reactiveObj) {
// 每个 DOM 节点关联一个响应式代理或 effect
const record = {
proxy: reactiveObj,
deps: new Set(), // 依赖的响应式字段集合
update() { /<em> 触发视图更新 </em>/ }
};
elementToReactiveMap.set(el, record);
}</p><p>function getReactiveRecord(el) {
return elementToReactiveMap.get(el) || null;
}</p><p>// 组件卸载时无需显式 delete —— WeakMap 自动失效</p>注意:不能对 el 做 JSON.stringify 或当 key 存进普通对象,否则失去弱引用特性;也不能用 el.id 或 el.dataset.id 替代 —— ID 可重复、可篡改、无类型安全。










