引言
在还没认识ES6的Set对象之前,我一直使用JS的原生数组Array的方法,虽然在开发中一样能实现想要的效果,但在使用Set之后,不得不说一句真香。
作为开发者首先要明白,为什么ES会设计一种新的数据结构去替代Array的部分使用场景,本文将一点点讲解Set跟Array的区别跟各自的优势和应用场景。
Set跟Array最明显的区别就是它的成员的值是唯一的,它在prototype上的方法相对Array比较简洁和直观。同时可以看出来Set对象是继承自Object对象。
基本用法
只能用new去定义一个Set对象,可以接受一个数组作为参数初始化
const a = new Set()
[...a] // []
const b = new Set([1,2,3,4,5,5,5])
[...b] // [ 1, 2, 3, 4, 5 ]
Set对象可用于数组去重
由于成员的值是唯一的,因此上述b的成员不会出现同样的元素5 利用这一特性,可用下面的方法给数组去重
[...new Set([arr])
同时也可给字符串清除重复字符
[...new Set('aaabnbv')].join('') // abnv
操作方法
常用的方法有四种add,delete,has,clear
add
添加元素,返回 Set 结构本身
a.add(1).add(2).add(1);
a.size // 2
has
判断是否为成员,返回一个Boolean
[...a] // [1,2]
a.has(1) // true
a.has(2) // true
a.has(3) // false
跟普通Array对象的判断成员方法对比,跟ES6新出的includes异曲同工,但比传统的indexOf更简洁
const arr = [...a]
// 使用includes
arr.includes(1) // true
arr.includes(2) // true
arr.includes(3) // false
// 使用indexOf
arr.indexOf(1)==-1 // false
arr.indexOf(2)==-1 // false
arr.indexOf(3)==-1 // true
跟普通Object对象对比
a[key]
delele
删除某个值,返回一个布尔值,表示删除是否成功
[...a] // [1,2]
a.delete(1) // true
a.delete(4) // false
a // 2
clear
清除所有成员,没有返回值
a.clear() // undefined
a // Set(0) {}
遍历方法
Set.prototype.keys():返回键名的遍历器Set.prototype.values():返回键值的遍历器Set.prototype.entries():返回键值对的遍历器Set.prototype.forEach():使用回调函数遍历每个成员
keys(),values(),entries()
由于Set没有键名,所以keys,values的效果一样,entries则返回一个数组,两个成员都是Set的值。
let set = new Set([1,2,3]);
for (let item of set.keys()) {
console.log(item);
}
// 1
// 2
// 3
for (let item of set.entries()) {
console.log(item);
}
// [1, 1]
// [2, 2]
// [3, 3]
forEach
用于遍历Set对象中的值,同上这里的value跟key是一样的
set.forEach( (value,key) => {
console.log(value)
})
同时,map和filter也可以间接用于Set
let set = new Set([1, 2, 3]);
set = new Set([...set].map(x => x * 2));
// 返回Set结构:{2, 4, 6}
let set = new Set([1, 2, 3, 4, 5]);
set = new Set([...set].filter(x => (x % 2) == 0));
// 返回Set结构:{2, 4}
WeakSet
还有一个Set对象的衍生品WeakSet,用于处理其他情况。 可以看出来它具备部分的Set语法,但有两个区别
成员只能对象
const weak = new WeakSet()
weak.add(1)
弱引用:垃圾回收不考虑
了解V8垃圾回收机制的应该知道,当一个对象还能被访问到,回收机制将不会释放该内存,当使用后没有释放该内存,容易引发内存泄漏。 但在WeakSet里面引用的对象,不会计入回收机制,当该对象不能被访问后,系统将会清除该对象,而不考虑它被WeakSet引用了。在此之后,它在WeakSet里面的引用就消失了。 由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。
WeakSet 无法遍历
WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏
使用Set的优势
从根本上来说,Array是根据索引排序,而Set是根据插入顺序迭代。主要优势体现在以下几个方面
- 查看元素:has比includes,indexOf的查看速度要快
- 删除元素:可根据值去删除元素,而Array只能通过splice+索引的方式,对索引的依赖更大
- 无重复元素:上述已说明
但创建元素的方法,Array会比Set速度更快。
有一篇文章对比不同数据量下两种对象的速度,可以参考一下 juejin.cn/post/684490…