--- title: WeakSet slug: Web/JavaScript/Reference/Global_Objects/WeakSet tags: - WeakSet translation_of: Web/JavaScript/Reference/Global_Objects/WeakSet ---
WeakSet
对象允许你将弱保持对象存储在一个集合中。
new WeakSet([iterable]);
WeakSet
对象中。null 被认为是 undefined。WeakSet
对象var ws = new WeakSet(); var foo = {}; var bar = {}; ws.add(foo); ws.add(bar); ws.has(foo); // true ws.has(bar); // true ws.delete(foo); // 从set中删除 foo 对象 ws.has(foo); // false, foo 对象已经被删除了 ws.has(bar); // true, bar 依然存在
注意, foo !== bar
。 尽管它们是相似的对象,但是它们不是同一个对象。因此,它们都可以被加入到set中。
WeakSet
对象是一些对象值的集合, 并且其中的每个对象值都只能出现一次。在WeakSet
的集合中是唯一的
它和 {{jsxref("Set")}} 对象的区别有两点:
Set
相比,WeakSet
只能是对象的集合,而不能是任何类型的任意值。WeakSet
持弱引用:集合中对象的引用为弱引用。 如果没有其他的对WeakSet
中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 正因为这样,WeakSet
是不可枚举的。递归调用自身的函数需要一种通过跟踪哪些对象已被处理,来应对循环数据结构的方法。
为此,WeakSet非常适合处理这种情况:
// 对 传入的subject对象 内部存储的所有内容执行回调 function execRecursively(fn, subject, _refs = null){ if(!_refs) _refs = new WeakSet(); // 避免无限递归 if(_refs.has(subject)) return; fn(subject); if("object" === typeof subject){ _refs.add(subject); for(let key in subject) execRecursively(fn, subject[key], _refs); } } const foo = { foo: "Foo", bar: { bar: "Bar" } }; foo.bar.baz = foo; // 循环引用! execRecursively(obj => console.log(obj), foo);
在此,在第一次运行时创建WeakSet
,并将其与每个后续函数调用一起传递(使用内部参数_refs)。 对象的数量或它们的遍历顺序无关紧要,因此,WeakSet比{{jsxref("Set")}}更适合(和执行)跟踪对象引用,尤其是在涉及大量对象时。
WeakSet.length
length
属性的值为 0.WeakSet
构造函数的原型。 允许向所有WeakSet
对象添加属性。WeakSet
实例所有 WeakSet
实例都继承自 {{jsxref("WeakSet.prototype")}}.
{{page('zh-CN/Web/JavaScript/Reference/Global_Objects/WeakSet/prototype','Properties')}}
{{page('zh-CN/Web/JavaScript/Reference/Global_Objects/WeakSet/prototype','Methods')}}
规范链接 | 规范状态 | 备注 |
{{SpecName('ES2015', '#sec-weakset-objects', 'WeakSet')}} | {{Spec2('ES2015')}} | Initial definition. |
{{SpecName('ESDraft', '#sec-weakset-objects', 'WeakSet')}} | {{Spec2('ESDraft')}} |
{{Compat("javascript.builtins.WeakSet")}}