WeakSet
一、认识
WeakSet 是ES6
新增的一种弱集合类型,为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);