WeakMap 用于存储“目标→订阅者集合”的弱引用映射,避免内存泄漏;其键为弱引用对象,目标销毁后对应条目自动清理,但需确保回调不强持有目标,且不支持遍历。

WeakMap 可以用来存储观察者(订阅者)的弱引用,避免内存泄漏,但它本身不直接支持“弱引用观察者”逻辑——关键在于如何设计结构,让订阅者对象能被垃圾回收,同时仍能触发通知。
为什么用 WeakMap?
在观察者模式中,若把订阅者存进普通 Map 或数组,即使外部已丢弃该订阅者对象,它仍被强引用,无法回收。WeakMap 的键是弱引用,当订阅者对象(作为 key)不再被其他地方引用时,整个键值对可被自动清理,从而实现自动解绑。
注意:WeakMap 的 key 必须是对象,且只支持 get/set/delete,不支持遍历或 keys() —— 这恰恰防止了意外强持有。
典型实现结构
常见做法是将目标对象(如被观察的数据项)作为 WeakMap 的 key,对应 value 是一个 Set 或 Map,存该目标上的所有订阅者回调:
立即学习“Java免费学习笔记(深入)”;
- WeakMap 存的是「目标 → 订阅者集合」映射,目标对象作为 key 是弱引用
- 订阅者回调本身通常存为函数,如果它们不闭包持有目标对象,一般不会阻止目标回收
- 真正要弱化的不是回调函数,而是「谁订阅了谁」的关系:目标销毁后,其对应的订阅者集合自然失效
一个安全的简易示例
假设我们观察某个配置对象的变化:
const observers = new WeakMap(); // key: target obj, value: Set of callbacks
function observe(target, callback) {
if (!observers.has(target)) {
observers.set(target, new Set());
}
observers.get(target).add(callback);
}
function notify(target, data) {
const callbacks = observers.get(target);
if (callbacks) {
for (const cb of callbacks) cb(data);
}
}
// 使用
const config = { theme: 'dark' };
observe(config, () => console.log('config changed'));
notify(config, { theme: 'light' });
// config 被设为 null 后,WeakMap 中该条目自动消失,无内存泄漏
config = null;
注意事项与局限
- WeakMap 不解决「回调函数内部强引用目标」的问题 —— 若 callback 里长期持有 target 引用,target 仍无法回收
- 无法主动枚举所有活跃订阅者,适合「按需触发」场景,不适合需要手动取消全部监听的管理方式
- 若需支持取消单个订阅,可在 observe 返回一个 cleanup 函数,内部从 Set 中 delete;这不依赖 WeakMap 的弱性,但配合使用更健壮


















