WeakMap 和 WeakSet 的核心价值在于持有弱引用,不阻止垃圾回收,适合缓存、元数据绑定或私有属性模拟;WeakMap 键必须是对象,支持私有数据存储与自动清理;WeakSet 仅存对象,用于标记且不可遍历。

WeakMap 和 WeakSet 的核心价值在于:它们持有的引用是“弱引用”,不阻止垃圾回收器释放对应的对象。这使得它们天然适合做缓存、元数据绑定或私有属性模拟,而不会因意外持有对象导致内存无法释放。
WeakMap:为对象添加不干扰生命周期的私有数据
WeakMap 的键必须是对象,且这个引用是弱的——如果某个对象只被 WeakMap 的键引用,而其他地方都不再持有它,那么该对象会被正常回收,WeakMap 中对应的条目也会自动消失。
常见用途:
- 给第三方对象(比如 DOM 元素或用户传入的实例)附加临时状态,又不想修改其原型或增加属性(避免污染和冲突)
- 实现对象级别的缓存,例如函数结果缓存(memoization),当输入对象被销毁,缓存项也自动失效
- 模拟“私有字段”:类内部用 WeakMap 存储实例专属数据,外部无法直接访问,也不影响实例回收
示例:
立即学习“Java免费学习笔记(深入)”;
const cache = new WeakMap();function expensiveCalc(obj) {
if (cache.has(obj)) return cache.get(obj);
const result = /* 耗时计算 */;
cache.set(obj, result);
return result;
}
一旦 obj 被销毁,cache 中对应项随之清理,无需手动维护。
WeakSet:标记对象而不延长其存活时间
WeakSet 只能存储对象,同样使用弱引用。它不支持遍历、size 查询或 clear,正是为了不产生对内部对象的强持有。
典型场景:
- 记录一组“已处理过”的对象(如防止重复初始化),对象销毁后标记自然消失
- 在事件监听或异步回调中跟踪对象是否仍有效(配合 if (weakSet.has(obj)) 判断)
- 避免循环引用导致的泄漏:比如父子对象互相引用时,用 WeakSet 替代普通 Set 存储子项列表
与普通 Map/Set 的关键区别
普通 Map/Set 持有强引用,只要条目存在,键/值就不会被回收——这是内存泄漏的常见源头。
WeakMap/WeakSet 不提供 keys()、values()、entries() 或 size,因为它们的内容随时可能变化(由 GC 决定),无法可靠枚举;这也强制开发者接受“弱引用不可控”的事实,避免误用。
注意:WeakMap 的键只能是对象(不能是字符串、数字等原始值),WeakSet 同理;这是设计使然,因为只有对象才涉及复杂的生命周期管理。
它们不是万能的,但解决了特定痛点
WeakMap 和 WeakSet 不解决所有内存问题,比如闭包中意外保留大对象、定时器未清除、全局变量引用等。它们只解决“因数据结构自身引用导致的对象无法释放”这一类泄漏。
真正起作用的前提是:目标对象除了在 WeakMap/WeakSet 中,没有其他强引用。如果还有变量、数组、DOM 属性等持有着它,那它依然不会被回收。











