WeakSet 不提供 size 和遍历能力,因其设计目标是“弱存在性登记册”,仅通过 has() 判断对象是否尚未被 GC 回收;size 不稳定、遍历会引发强引用,故规范禁止 clear、迭代器等操作,且只接受对象类型。

WeakSet 为什么连 size 都不给?
因为它根本不能、也不该知道“自己存了几个对象”。WeakSet 的设计目标不是做容器,而是做“弱存在性登记册”——只管记一笔“这个对象我见过”,但绝不阻拦 GC 回收它。一旦对象被回收,对应条目就自动消失,size 就失去了稳定定义的基础。
- GC 可能在任意时刻清理对象,
size值随时可能突变,返回一个瞬间过期的数字反而误导人 - 如果暴露
size,引擎就必须在内部维护计数器,这会引入额外同步开销,违背“轻量弱引用”的初衷 - 所有主流引擎(V8、SpiderMonkey、JavaScriptCore)都刻意不实现
size,不是遗漏,是共识
遍历 WeakSet 为什么被彻底禁止?
因为遍历行为本身就会构成强引用——你正在“访问”它,引擎无法判断你是想读数据,还是无意中把它钉在内存里。所以连 keys()、values()、forEach()、[Symbol.iterator] 全部砍掉。
- 哪怕只是写
for (const item of weakSet) { ... },语法上就直接报TypeError: weakSet is not iterable -
Array.from(weakSet)同样失败,因为依赖迭代器接口 - 这不是兼容性问题,是语言规范硬性限制(ECMA-262 §23.4.1.1),任何 polyfill 都无法真正模拟
那怎么知道某个对象还在不在 WeakSet 里?
唯一合法且安全的方式只有 has()。它不触发遍历,不暴露数量,只做一次弱引用快照比对。
-
weakSet.has(obj)返回true,只代表“此刻 obj 还没被 GC”;返回false,可能是没加过,也可能是刚被回收 - 别用
has()做状态轮询——比如循环检测!weakSet.has(obj)等它消失,这既不可靠,又浪费 CPU - 典型用法是配合闭包或私有状态:比如在类方法里用
weakSet.has(this)判断是否已初始化,避免重复 setup
误用 WeakSet 当普通集合的常见翻车点
很多人一看到“Set”就下意识当成 Set 的轻量版,结果踩进语义陷阱。
- 试图用
weakSet.clear()—— 方法根本不存在,会报TypeError: weakSet.clear is not a function - 想用
[...weakSet]解构取值 —— 报错TypeError: weakSet is not iterable - 拿
WeakSet存基本类型(如'id1'、42)—— 会静默失败,因为 WeakCollection 只接受对象,其他类型直接被忽略(不报错但也不存) - 在调试时打印
weakSet,Chrome 控制台显示WeakSet { … },但点不开内容——这不是 bug,是故意隐藏,防止开发者产生“能看就能遍历”的错觉
size 不是功能缺失,而是边界声明:它只回答一个问题——“这个对象,此刻还活着吗?”多一个字都不说。

















