Weakmap和WeakSet的核心特性是键或值的弱引用不阻止垃圾回收。WeakMap只接受对象作键、不可遍历;WeakSet只存对象、无size属性且不可遍历;二者均不触发GC,也不能用于缓存或序列化。

WeakMap 和 WeakSet 的核心特性不是“弱引用”本身,而是它们对键(WeakMap)或值(WeakSet)的引用不阻止垃圾回收——这意味着你无法通过它们“持有”对象而不影响其生命周期。
WeakMap 只接受对象作为键,且无法遍历
WeakMap 的 key 必须是对象(包括函数、数组、普通对象),传入原始值(如 "str"、42、true)会直接报错:TypeError: Invalid value used as weak map key。它没有 keys()、values()、entries() 或 forEach 方法,也无法用 for...of 遍历。
常见用途是给第三方对象“附加私有元数据”,又不干扰其回收:
const privateData = new WeakMap(); class Button { constructor(el) { this.el = el; privateData.set(el, { clickedCount: 0, lastClickTime: Date.now() }); } click() { const data = privateData.get(this.el); data.clickedCount++; } }
如果 el 被 dom 移除且无其他引用,它连同 privateData 中对应的条目会被 GC 回收。
立即学习“Java免费学习笔记(深入)”;
WeakSet 只存对象,且不能查 size 或遍历
WeakSet 的成员只能是对象,同样拒绝原始值;它没有 size 属性,也没有 has() 以外的查询方法(注意:has() 是可用的);也不能遍历。它的典型场景是标记“已处理对象”,避免重复操作:
示例:
const processed = new WeakSet(); function process(obj) { if (processed.has(obj)) return; // ...实际处理逻辑 processed.add(obj); }
只要 obj 外部引用消失,processed 不会阻止它被回收。
WeakMap/WeakSet 不触发 GC,也不保证立即清理
它们不控制垃圾回收时机,只“不阻碍”回收。即使对象已无强引用,GC 也可能尚未运行,此时 get() 或 has() 仍可能返回值。不能依赖它们做“资源释放通知”或“生命周期钩子”。
- 不要用
WeakMap.get(key) === undefined判断对象是否已被回收——它可能只是没设过,或刚设完还没 GC - 不能用 WeakMap 实现缓存(比如 LRU),因为无法枚举、无法控制淘汰逻辑
- node.js 中可通过
global.gc()(需启动时加--expose-gc)辅助测试,但生产环境禁用
与 Map/Set 的关键差异总结
WeakMap/WeakSet 的限制全是为支持弱引用让路:
-
Map键可以是任意类型;WeakMap键只能是对象 -
Set用Object.is()比较值;WeakSet同样只靠引用相等,但无法迭代验证 -
Map.prototype.clear()存在;WeakMap没有clear(),也无法清空——设计上就不可逆 - 序列化(
jsON.stringify)对 WeakMap/WeakSet 无意义,它们不会出现在任何序列化结果中
真正需要弱引用语义时才用它们;想存配置、缓存、索引,还是老实用 Map/Set —— 弱引用不是免费午餐,是带约束的取舍。