跳到主要内容

WeakSet

一、认识


WeakSetES6 新增的一种弱集合类型,为JavaScript带来了集合数据解构,描述的是JavaScript中垃圾回收程序对待弱集合中值的方式,不会阻止垃圾回收。WeakSet中对象的引用为弱引用WeakSet 中的值任何时候都可能被销毁,所以没必要提供其迭代遍历其值的能力。

二、语法


2.1 new WeakSet()

const weakSet = new WeakSet();
console.log(weakSet); // WeakSet {}

2.2 new WeakSet([对象数组])

注意: 弱集合中的元素值必须是 Object 或者 继承自Object 的类型,如果使用非对象设置元素值会抛出异常 原因: 为了保证只有通过值对象的引用才能取得其值。如果允许基本数据类型设置其值,那么没办法区分初始化时使用的字符串字面量初始化后使用的一个相等的字符串了。

const weakSet = new WeakSet([{id:1},{id:2}]);
console.log(weakSet); // WeakSet {{…}, {…}}

三、属性


四、方法


4.1 weakSet.add() 新增元素

weakSet.add() 新增元素,并且返回WeakSet实例,因此**WeakSet实例.add()**可以链式调用。注意: 弱集合中的元素值必须是 Object 或者 继承自Object 的类型,如果使用非对象设置元素值会抛出异常

语法

单个使用
const weakSet = new WeakSet();
weakSet.add({id:1});
weakSet.add({id:2});
console.log(weakSet); // WeakSet {{…}, {…}}
链式调用
const weakSet = new WeakSet();
weakSet.add({id:1}).add({id:2});
console.log(weakSet); // WeakSet {{…}, {…}}
细节

WeakSet 添加 null 时,会被当作undifined处理,直接报错。

const weakSet = new WeakSet();
weakSet.add(null);
console.log(weakSet); // Invalid value used in weak set

4.2 weakSet.has()

语法

const obj1 = {id:1};
const obj2 = {id:2};
const weakSet = new WeakSet([obj1,obj2]);
console.log(weakSet.has(obj1)); // true

4.3 weakSet.delete()

weakSet.delete() 删除Set实例中的指定元素,返回一个布尔值,表示集合中是否存在要删除的值。

语法

const obj1 = {id:1};
const obj2 = {id:2};
const weakSet = new WeakSet([obj1,obj2]);
console.log(weakSet); // WeakSet {{…}, {…}}
weakSet.delete(obj1);
console.log(weakSet); // WeakSet {{…}}

4.4 weakSet.clear()

WeakSet中对象的引用为弱引用WeakSet 中的值任何时候都可能被销毁,所以没必要提供 clear() 一次性销毁所有值的方法。

五、对比


5.1 Set Vs WeakSet


WeakSet对象是一些对象值的集合, 并且其中的每个对象值都只能出现一次。在WeakSet的集合中是唯一的。它和Set对象的区别有两点:

  • Set相比,WeakSet只能是对象的集合,而不能是任何类型的任意值。
  • WeakSet持弱引用:集合中对象的引用为弱引用。 如果没有其他的对WeakSet中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 正因为这样,WeakSet是不可枚举的。

六、场景


6.1 检测循环引用

递归调用自身的函数需要一种通过跟踪哪些对象已被处理,来应对循环数据结构的方法。为此,WeakSet非常适合处理这种情况。

function execRecursion(fn,subject,ref=null){
if(!ref){
ref = new WeakSet();
}
if(ref.has(subject)){
return
}
fn(subject);
if(typeof subject === "object"){
ref.add(subject);
for(let key in subject){
execRecursion(fn,subject[key],ref);
}
}
}

const obj = {
type:'obj',
data:{
type:'dataObj',
}
}
obj.data.data = obj; // 设置循环引用

function foo(obj){
console.log(obj);
}
execRecursion(foo,obj);