weakmap 是为外部对象无侵入挂载扩展属性的最佳方式——不污染原对象、不改变原型链、不暴露数据且随对象自动销毁;需校验键为合法对象,通过封装方法访问,并避免反向引用。

WeakMap 是插件化架构中为外部对象“挂载扩展属性”最干净的方式——它不往原对象上加任何字段,不改变其原型链,也不暴露扩展数据,同时还能随对象自动销毁。
用 WeakMap 做无侵入式扩展
插件常需给用户传入的第三方对象(如 DOM 元素、配置实例、框架组件)添加临时状态或增强能力,但直接在对象上赋值(el._pluginData = {...})会污染原对象,破坏封装性,还可能与已有属性冲突。
- WeakMap 把扩展数据存在外部存储中,键是那个外部对象本身,值是你想挂载的数据
- 原对象保持“原样”,
console.dir(el)看不到任何新增字段,for...in或Object.keys()也遍历不到 - 只要插件模块里持有 WeakMap 引用,其他代码就无法通过反射或调试器访问这些扩展属性
确保键合法且安全
WeakMap 要求键必须是对象,且不能是 null、undefined 或原始值。插件接收外部对象时需做类型防护:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 对 DOM 元素:检查
node instanceof Node,避免传入字符串 ID 或 document.getElementById() 返回 null 的情况 - 对普通对象(如用户传入的配置实例):可约定必须是特定类的实例,或至少是 plain object(
node && typeof node === 'object' && node !== null) - 禁止把 window、document、函数等全局对象作为键——它们生命周期太长,违背 WeakMap “随对象消亡”的设计初衷
配合原型方法提供统一访问接口
插件不应暴露 WeakMap 实例本身,而应通过封装好的方法来读写扩展属性:
- 在插件类的 prototype 上定义
getExtData()、setExtData(key, value)等方法 - 方法内部调用
extStore.get(this.target) || {}获取当前对象专属的扩展数据对象 - 所有插件实例共享同一个模块级 WeakMap,既节省内存,又保证隔离性——每个对象的数据彼此不可见
让扩展属性随对象自然消亡
这是 WeakMap 区别于 Map 的核心价值:当外部对象被框架卸载、DOM 移除或变量置为 null 后,只要没有其他强引用,GC 就会回收该对象,WeakMap 中对应条目也同步失效。
- 无需监听
DOMNodeRemoved、unmount或手动调用delete - 特别适合动态插件场景:比如富文本编辑器里,工具栏按钮被切换关闭,其关联的拖拽状态、缓存标记自动消失
- 注意避免反向引用:扩展数据对象里不要保存对原对象的强引用(如
{ owner: el }),否则会阻止 GC
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










