WeakSet
Baseline 广泛可用 *
WeakSet 是一种可垃圾回收的值的集合,包括对象和未注册的 Symbol。WeakSet 中的值只能出现一次。在 WeakSet 的集合中是唯一的。
描述
WeakSet 的值必须是可垃圾回收的。大多数原始数据类型可以任意创建且没有生命周期,因此不能存储。对象和未注册的 Symbol 可以存储,因为它们是可垃圾回收的。
与Set 对象的主要区别在于
-
WeakSet仅包含对象和 Symbol。它们不能包含任意类型的值,而Set可以。 -
WeakSet是弱的,这意味着对WeakSet中对象的引用是弱引用。如果WeakSet中存储的值没有其他引用存在,这些值就可以被垃圾回收。注意:这也意味着集合中没有存储当前值的列表。
WeakSet是不可枚举的。
键的相等性
与常规 Set 一样,值相等性基于SameValueZero 算法,该算法与 === 运算符相同,因为 WeakSet 只能包含对象和 Symbol 值。这意味着对于对象值,相等性基于对象标识。它们是通过引用而不是值进行比较的。
构造函数
WeakSet()-
创建一个新的
WeakSet对象。
实例属性
这些属性定义在 WeakSet.prototype 上,并由所有 WeakSet 实例共享。
WeakSet.prototype.constructor-
创建实例对象的构造函数。对于
WeakSet实例,初始值为WeakSet构造函数。 WeakSet.prototype[Symbol.toStringTag]-
[Symbol.toStringTag]属性的初始值为字符串"WeakSet"。此属性用于Object.prototype.toString()。
实例方法
WeakSet.prototype.add()-
将指定值插入此集合,如果尚不存在。
WeakSet.prototype.delete()-
如果指定值存在于此集合中,则将其从集合中移除。
WeakSet.prototype.has()-
返回一个布尔值,指示指定值是否存在于此
WeakSet中。
示例
使用 WeakSet 对象
const ws = new WeakSet();
const foo = {};
const bar = {};
ws.add(foo);
ws.add(bar);
ws.has(foo); // true
ws.has(bar); // true
ws.delete(foo); // removes foo from the set
ws.has(foo); // false, foo has been removed
ws.has(bar); // true, bar is retained
请注意,foo !== bar。虽然它们是相似的对象,但它们不是同一个对象。因此它们都被添加到了集合中。
检测循环引用
递归调用的函数需要一种方法来防止循环数据结构,通过跟踪哪些对象已经被处理。
WeakSet 非常适合此目的
// Execute a callback on everything stored inside an object
function execRecursively(fn, subject, _refs = new WeakSet()) {
// Avoid infinite recursion
if (_refs.has(subject)) {
return;
}
fn(subject);
if (typeof subject === "object" && subject) {
_refs.add(subject);
for (const key in subject) {
execRecursively(fn, subject[key], _refs);
}
_refs.delete(subject);
}
}
const foo = {
foo: "Foo",
bar: {
bar: "Bar",
},
};
foo.bar.baz = foo; // Circular reference!
execRecursively((obj) => console.log(obj), foo);
在此,WeakSet 在第一次运行时创建,并在每次后续函数调用时(使用内部 _refs 参数)传递。
对象的数量或它们的遍历顺序并不重要,因此 WeakSet 比 Set 更适合(且性能更好)来跟踪对象引用,尤其是当涉及大量对象时。
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # sec-weakset-objects |
浏览器兼容性
加载中…