日常学习2024.03.12-js中的weakSet

21 篇文章 0 订阅
11 篇文章 0 订阅
本文解释了WeakSet在JavaScript中的作用,它是可被垃圾回收的对象和非全局注册符号的集合。与Set的主要区别在于WeakSet使用弱引用,当对象没有其他强引用时,即使在WeakSet中也会被回收,避免内存泄漏。同时,文章通过示例展示了WeakSet与Set在引用行为上的差异。
摘要由CSDN通过智能技术生成

1.WeakSet是什么?

weakSet是什么呢?刚开始自己确实也没什么印象,终结学习一下吧。

WeakSet 是可被垃圾回收的值的集合,包括对象和非全局注册的符号(Symbol基本数据类型)。WeakSet 中的值只能出现一次。它在 WeakSet 的集合中是唯一的。

WeakSet 中的值一定是可被垃圾回收的值。大多数原始数据类型可以被任意地创建,并且没有生命周期,所以它们不能被存储。对象和非全局注册的符号可以被存储,因为它们是可被垃圾回收的值。

它和 Set 对象的主要区别有:

WeakSet 只能是对象和符号的集合,它不能像 Set 那样包含任何类型的任意值。
WeakSet 持弱引用:WeakSet 中对象的引用为弱引用。如果没有其他的对 WeakSet 中对象的引用存在,那么这些对象会被垃圾回收。

第一个区别好理解

const ws = new WeakSet();
ws.add(1) // 报错,Uncaught TypeError: Invalid value used in weak set
ws.add(Symbol()) // 不报错

第二个区别就有点懵了

2.WeakSet 使用弱引用,Set使用强引用

WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

这是因为垃圾回收机制根据对象的可达性(reachability)来判断回收,如果对象还能被访问到,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。

由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。

举个例子

let weakSet = new WeakSet();

// 创建两个对象
let obj1 = { name: 'Object 1' };
let obj2 = { name: 'Object 2' };

// 将对象添加到 WeakSet 中
weakSet.add(obj1);
weakSet.add(obj2);

console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj2)); // true

// 移除对 obj1 的引用
obj1 = null;

// 在这里,obj1 不再有任何强引用,可以被垃圾回收

console.log(weakSet.has(obj1)); // false
console.log(weakSet.has(obj2)); // true```

在上述示例中,我们创建了一个 WeakSet 实例 weakSet,并将两个对象 obj1 和 obj2 添加到其中。我们可以使用 has 方法检查对象是否存在于 WeakSet 中。

随后,我们将 obj1 的引用设置为 null,从而删除了对它的强引用。此时,obj1 不再有任何强引用,因此它可以被垃圾回收。

在最后的两个 console.log 语句中,我们可以看到 weakSet.has(obj1) 返回 false,表示 obj1 已经从 WeakSet 中被移除。而对于 obj2,它仍然存在于 WeakSet 中,因为它仍有一个强引用。

但是如果将WeakSet换成Set呢

let et = new Set();

// 创建两个对象
let obj1 = { name: 'Object 1' };
let obj2 = { name: 'Object 2' };

// 将对象添加到 WeakSet 中
et.add(obj1);
et.add(obj2);

console.log(et.has(obj1)); // true
console.log(et.has(obj2)); // true

// 移除对 obj1 的引用
obj1 = null;
console.log(et.has(obj1)); // false
console.log(et.has(obj2)); // true

结果还是一样的!那Set和WeakSet的第二个区别不就没有区别了吗。其实不是的
在上面的代码中,即使我们将 obj 设置为 null,Set 中的对象仍然不会被垃圾回收,因为 Set 本身保持了对它的强引用。如果我们试图检查 set.has(obj),由于 obj 是 null,这个检查没有意义。要正确检查 Set 是否包含对象,我们需要一个有效的引用到那个对象,这在我们的例子中是不存在的。
改一下代码

// 创建一个对象  
let obj1 = { name: "Example1" };  
  
// 创建一个 Set 并将对象添加进去  
let set = new Set();  
set.add(obj1);  
  
// 此时,set 包含了对 obj1 的强引用  
  
// 创建另一个引用,指向同一个对象  
let obj2 = obj1;  
  
// 移除 obj1 引用,但 obj2 仍然引用着对象  
obj1 = null;  
  
// 使用 obj2 检查对象是否仍然在 set 中  
console.log(set.has(obj2)); // 输出 true,因为 obj2 仍然引用着对象,且对象在 set 中  
  
// 现在,如果我们没有其他引用指向对象,并且尝试重新构造一个看似相同的对象,  
// 它将不会被视为同一个对象,因为对象在 JavaScript 中是通过引用比较的  
let obj3 = { name: "Example1" }; // 这是一个新的对象,与之前的 obj1 不是同一个引用  
  
console.log(set.has(obj3)); // 输出 false,因为 obj3 是一个新的对象,尽管它的内容看起来与 set 中的对象相同

这个例子就能说明WeakSet 使用弱引用,这意味着如果没有其他强引用指向对象,对象可以被垃圾回收;而 Set 使用强引用,即使没有其他变量引用对象,Set 也会保持对象不被回收。
好好理解下,如果有问题欢迎指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值