weakmap 是实现无侵入对象属性扩展的理想工具,因其键必须为对象且弱引用,不修改原对象、不污染属性、可自动回收关联数据,适用于私有元数据缓存与封装。

WeakMap 是实现无侵入对象属性扩展的理想工具——它不修改原对象、不污染对象自身属性、且能随对象自动回收,真正做到了“附着式存储”。
为什么 WeakMap 能做到无侵入?
WeakMap 的键必须是对象(不能是原始值),且对键对象是弱引用:只要该对象在外部没有其他强引用,即使它作为 WeakMap 的键存在,垃圾回收器仍可将其回收。这意味着:
- 你无需在目标对象上添加任何属性(比如
_meta或Symbol.for('ext')) - 不会触发
Object.defineProperty或Proxy等可能干扰对象行为的机制 - 对象被销毁后,关联数据自动消失,无内存泄漏风险
典型用法:给任意对象挂载私有元数据
例如,为 DOM 元素缓存计算结果,又不想污染其属性:
const elementCache = new WeakMap();
function getComputedHeight(el) {
if (elementCache.has(el)) {
return elementCache.get(el);
}
const height = el.getBoundingClientRect().height;
elementCache.set(el, height); // 不改 el,不加 property
return height;
}
// 使用示例
const div = document.createElement('div');
console.log(getComputedHeight(div)); // 计算并缓存
console.log(getComputedHeight(div)); // 直接返回缓存值
// div 被移除、销毁后,cache 中对应条目自动失效
进阶技巧:配合闭包封装私有状态
多个模块共享同一个 WeakMap 实例时,需注意命名冲突。更安全的做法是将 WeakMap 封装在模块作用域内:
// utils/tooltip.js
const tooltipState = new WeakMap();
export function showTooltip(el, content) {
tooltipState.set(el, { visible: true, content });
}
export function hideTooltip(el) {
const state = tooltipState.get(el);
if (state) state.visible = false;
}
export function isTooltipVisible(el) {
return tooltipState.get(el)?.visible === true;
}
// 外部无法访问 tooltipState,也无法误删/覆盖其他模块的数据
注意事项与边界情况
WeakMap 的“弱引用”特性也带来一些限制,使用前需明确:
-
不能遍历:没有
keys()、values()、entries()方法,无法枚举所有键值对 - 键只能是对象:不能用字符串、数字、Symbol 作键(想用字符串映射请用 Map)
-
无法检测是否被 GC:你只能通过
has()判断当前是否还“活着”,但无法得知它刚被回收 - 不适用于长期持有逻辑:如果需要确保某段数据始终存在,WeakMap 不适合——应改用 Map + 手动生命周期管理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











