WeakMap 键必须是对象且为弱引用,避免内存泄漏;不支持遍历、size 属性,仅提供 set/get/has/delete;适用于私有状态、元数据附加等场景。

WeakMap 为什么不能用普通对象或 Map 存键?
WeakMap 的核心约束是:键必须是 Object(包括函数、数组、DOM 元素等),且对键的引用是「弱引用」——也就是说,只要这个对象在其他地方不再被引用,它就能被垃圾回收器清理掉,即使它还作为 WeakMap 的键存在。
而普通对象当键时会自动转成字符串(比如 {a:1} → "[object Object]"),根本没法区分不同实例;Map 虽然支持任意类型作键,但它会强持有键对象,导致内存泄漏风险——尤其当你想把 DOM 元素或大型配置对象作为键来存私有数据时。
常见错误现象:
• 用 Map 缓存组件实例状态,但组件卸载后 DOM 元素仍驻留内存
• 试图用 {} 存多个 input 元素的校验结果,结果所有 input 都共享同一份 key
WeakMap 的典型使用场景有哪些?
它不是用来替代 Map 的通用容器,而是专为「附加元数据」和「避免内存泄漏」设计的。真实项目里最常遇到的几个点:
立即学习“Java免费学习笔记(深入)”;
- 给第三方类或原生对象(如
HTMLElement)添加私有属性,又不想污染原型或触发属性劫持 - 实现私有字段模拟(在
class语法普及前,很多库用 WeakMap 模拟#private) - 缓存计算结果,但只在目标对象存活期间有效(例如:某个 canvas 元素的渲染上下文缓存)
- 做轻量级事件绑定代理,绑定关系随目标对象销毁而自动失效
WeakMap 和 Map 的关键行为差异
别被名字误导——WeakMap 不是「弱一点的 Map」,它连基础遍历能力都没有。这些限制直接决定了你怎么用它:
-
WeakMap.prototype.keys()、.values()、.entries()全部不存在 —— 你无法枚举它的内容 -
WeakMap.prototype.size属性不存在 —— 它不提供长度信息 - 只能通过
set(key, value)、get(key)、has(key)、delete(key)四个方法操作 - 键一旦是原始值(如
"string"、42、true),调用set会直接抛错:TypeError: Invalid value used as weak map key
性能上,WeakMap 查找是 O(1),但因为不暴露内部结构,V8 等引擎可以更激进地优化内存管理,实际比 Map 更轻量(尤其在大量短生命周期对象场景下)。
一个真实的私有状态封装示例
假设你在写一个可复用的 Tooltip 类,需要为每个 tooltip 实例存储 DOM 引用、延时定时器等,又不想让这些数据暴露在实例上(避免被外部误改或枚举到):
const tooltipData = new WeakMap();
class Tooltip {
constructor(el) {
// el 必须是 object(比如 HTMLElement)
tooltipData.set(el, {
timer: null,
isVisible: false,
config: { delay: 300 }
});
el.addEventListener('mouseenter', () => this.show(el));
}
show(el) {
const data = tooltipData.get(el);
if (!data) return;
data.timer = setTimeout(() => {
data.isVisible = true;
// ... 显示逻辑
}, data.config.delay);
}
hide(el) {
const data = tooltipData.get(el);
if (data?.timer) {
clearTimeout(data.timer);
data.timer = null;
data.isVisible = false;
}
}
}
// 使用后,如果 el 被从 DOM 移除且无其他引用,tooltipData 中对应条目会自动消失
注意:这里 el 是键,不是字符串 ID;tooltipData 必须在闭包外声明(否则每次 new Tooltip 都新建一个 WeakMap,起不到跨实例共享的作用);一旦 el 被 GC,tooltipData.get(el) 就返回 undefined,不会报错。
最容易被忽略的一点:WeakMap 的「弱引用」只作用于键,值仍然会被强引用。所以如果你的 value 里又持有对 key 的引用(比如闭包里用了 el),照样会造成内存泄漏。










