weakset适合做私有标记,因其仅存储对象且使用弱引用,不阻止垃圾回收,可安全标记已处理/已初始化对象,避免内存泄漏;但不可存原始值,也不支持遍历或获取大小。

WeakSet 可以用来标记原始对象(实际指非原始值,即对象、函数等),且不阻止其被垃圾回收,适合实现轻量级私有状态标记。
为什么 WeakSet 适合做私有标记
WeakSet 的成员只能是对象,且对所存对象是弱引用——它不会阻止对象被垃圾回收。当你只想“记录某个对象是否被处理过”“是否启用某特性”或“是否属于某私有组”,又不想干扰内存生命周期时,WeakSet 比 Set 更安全。
例如:你有一个工具函数,需对传入的对象打上“已冻结”标记,但不希望因此让对象常驻内存;用 WeakSet 存储这些对象,一旦外部引用消失,它们就能正常被回收。
典型用法:标记已初始化/已处理的对象
常见于缓存、单次初始化、防重复操作等场景:
- 定义一个模块私有的 WeakSet 实例,比如 const initialized = new WeakSet()
- 在初始化逻辑开头检查 initialized.has(obj),避免重复执行
- 初始化完成后调用 initialized.add(obj)
这样既保证了逻辑幂等性,又不会因标记本身导致内存泄漏。
不能用于原始值,注意类型边界
WeakSet 不接受字符串、数字、布尔、null、undefined 等原始值,尝试添加会抛出 TypeError。所谓“原始对象”是误称——WeakSet 只能标记真正的对象(包括数组、函数、DOM 元素、class 实例等)。
如果需要为原始值(如 id 字符串)做类似标记,应改用 Map + 弱引用包装(如用 WeakMap 关联对象到原始值),或直接用普通 Map(需自行管理清理)。
对比 WeakMap:何时选哪个?
WeakSet 适合“仅需判断存在性”的场景;WeakMap 适合“需关联额外数据”的场景。
- 只关心“这个对象是否被标记过?”→ 用 WeakSet,更轻量
- 还需存储该对象对应的私有配置、缓存结果、元数据等→ 用 WeakMap
两者都保持弱引用,都不影响垃圾回收,选择取决于是否需要键值映射能力。










