写点什么

重学 JS | ES6 既有 Set,为啥还要有 Weak Set?

用户头像
梁龙先森
关注
发布于: 2021 年 01 月 24 日
重学JS | ES6既有Set,为啥还要有Weak Set?

先把标题问题解决了,再学习基础知识,知其前因后果。看段代码:

var obj = {a:1}var set = new Set()set.add(obj) // 移除原始引用obj = null// 输出:1,说明set中还是存在值,是不是null?console.log(set.size()) // 取出值看看 输出:div#set,并不是null[...set][0]  
复制代码

例子中变量 obj=null 时,便清除了对初始对象的引用,但是 Set 集合确保留了这个引用,这里可以通过展开运算符获取到引用值。也是因为 Set 集合对 obj 引用的存在,当 obj=null 时,垃圾回收机制就不能释放初始变量 obj 指向的对象内存空间。倘若你想让其他引用不再存在时,Set 集合中的这些引用也随之消息,就需要使用 Weak Set 集合,它是一种弱引用 Set 集合,只存储对象的弱引用,并且不可以存储原始值;集合中的弱引用如果是对象唯一的引用,则会被回收并释放相应内存。

var obj = {a:1}var weakSet = new WeakSet()weakSet.add(obj)// 清除引用obj = null// {} weak set中的引用也被删除console.log(weakSet) 
复制代码

回答完了问题,再看看相应的使用方法。

Set 集合

Set 是一种有序列表,其中包含的是一些相互独立的非重复值,通过 Set 可以快速访问其中的数据,更有效的追踪各种离散值。


Set 本身是一个构造函数,可以接受一个数组或者类数组对象作为参数。下面看看它的属性和函数:

属性

Set.prototype.constructor: 构造函数

Set.prototype.size: 返回实例的成员总数

方法

Set.prototype.add(value):添加一个值,返回 Set 结构本身

Set.prototype.delete(vallue):删除某个值,返回布尔值

Set.prototype.has(value):返回布尔值,表示是否是成员

Set.prototype.clear():清楚所有成员,无返回值

用法

1. add 详解

add 添加新值,与原有值比较采用的是严格相等("==="),只有不等的才能添加到 Set 实例中。其中有个例外:NaN,因为 NaN 与 NaN 在严格相等比较下是不相等的,但 Set 里面只能有个 NaN。

var set = new Set()set.add(1)set.add('1')set.add(1)// 1==='1' -> falseconsole.log(set) // Set(2) {1, "1"}
// NaN值var set1 = new Set()set1.add(NaN)set1.add(NaN)console.log(set1) // Set(1) {NaN} 添加了2个NaN,但输出只有1个
// 其他几种常规方法var set = new Set([1,2,3,4])set.delete(1) // true 删除成功,此时set:{2,3,4}set.has(3) // true 存在3set.size() // 3,删除了1个元素set.clear() // 清除集合所有元素,set:{}
复制代码
2. 数组去重
// 一维数组去重var arr = [1,1,2,2,3]var set = new Set(arr)console.log(set) // {1,2,3}
// 多数组合并去重var arr1 = [1,2,3]var arr2 = [1,2,3]var set1 = new Set([...arr1,...arr2]) console.log(set1) // {1,2,3}
复制代码
3. Set 与数组的转换
// 数组转为setvar arr = [1,2,3]var set = new Set(arr)
// set转为数组:Array.fromvar set = new Set()set.add(1).add(2)Array.from(set) // [1,2]// set转为数组:扩展运算符var arr = [...set] // [1,2]
复制代码
4. Set 的遍历
//1. forEachvar set = new Set([1,3,'ha'])set.forEach((item,idx)=>{	console.log(item,idx)})//输出: // 1 1// 3 3 3// 3 ha ha// 说明:传统forEach函数的第二个值是索引,但Set是键值对的集合,第二个参数表示键,实际上与第二个参数相同
// 2. keys 返回键名的遍历器for(let item of set.keys()){ console.log(item)}
// 3. values 返回键值的遍历器for(let item of set.values()){ // Set的键和值是相等的,所以keys和values返回的值是一样的 console.log(item) }// 4. entries() 返回键值对的遍历器for(let item of set.entries()){ console.log(item) // 输出的是[key,value]}
复制代码

Weak Set 集合

方法

支持 add()、has()和 delete()三个方法。例子如下:

var set = new WeakSet()var obj = {a:1}set.add(obj)  // 返回set实例 set.has(obj)  // trueset.delete(obj) // true,此时set:{}set.add(1) // 报错:TypeError: Invalid value used in weak set
复制代码

其他

Weak Set 集合不可迭代,不能被 for-of 循环。

Weak Set 集合不暴露任何迭代器,所以无法通过程序本身检测其中内容

Week Set 集合不支持 forEach 方法

Week Set 集合不支持 size 属性。


Weak Set 看似功能受限,实际上是为了让它能够正确的处理内存中的数据。

总结

至此学习了 Set 和 Weak Set 集合的使用,以及为啥有 Weak Set 集合。下一章学习 ES6 的 Map 集合。

发布于: 2021 年 01 月 24 日阅读数: 35
用户头像

梁龙先森

关注

脚踏V8引擎的无情写作机器 2018.03.17 加入

还未添加个人简介

评论

发布
暂无评论
重学JS | ES6既有Set,为啥还要有Weak Set?