持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
什么是Set
Set 是 ECMAScript 6 新增的一种新集合类型,它类似于数组,但是成员的值都是唯一的,没有重复的值,它为这门语言带来集合数据结构;
基本使用
Set 在很多方面都像是加强的 Map,因为他们大部分的 API 和行为都是共有的,所以如果看过我之前的文章 你知道JavaScript中的Map类型吗 应该也能很快的上手Set了
声明初始化
const set = new Set();
// Set(0) {size: 0}
初始化之后,可以使用 add()增加值,使用 has()查询,通过 size 取得元素数量,以及使用 delete()删除元素与 clear()清空集合;除了方法名有区别,具体使用与 Map 一致;
这里演示一下使用情况:
const set1 = new Set([1, 2, 3, 3, 4, 5]);
set1 // Set(5) { 1, 2, 3, 4, 5 }
set1.size // 5
set1.add(6) // Set(6) { 1, 2, 3, 4, 5, 6 }
[...set1] // [ 1, 2, 3, 4, 5 ]
set1.clear(); // 清空
set1.size // 0
Set特性
重复加入Set时,内部会使用“Same-value-zero equality” 算法来判断两个值是否不同,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为 NaN 不等于自身;
const set = new Set();
const a = NaN;
const b = NaN;
set.add(a);
set.add(b);
// 只有一个NaN
set // Set {NaN}
因此在使用.add API方法进行添加时会先判断是否存在,如果不存在就添加,存在就不添加;对于引用值而言,由于内存地址不同,即使是空对象会添加存储,不会进行去重操作,如下:
const set = new Set([1, 2, 3, 5, 6, 7]);
set.add(3).add(5).add(10).add({}).add({})
// Set(8) { 1, 2, 3, 5, 6, 7, {}, {} }
由于 Set 成员的值都是唯一的,具有去重效果,因此非常适合用于数组或字符串去重
const set = new Set([1,2,3,2,3]);
// Set(3) {1, 2, 3}
// 返回去重后的集合
Set 迭代操作
Set 会维护值插入时的顺序,因此支持按顺序迭代
集合实例可以提供一个迭代器(Iterator),能以插入顺序生成集合内容;
注意:Set 结构没有键名,只有键值(或者说键名和键值是同一个值)
Set 结构的实例有四个遍历方法,可以用于遍历成员:
-
Set.prototype.keys():返回键名的遍历器const set = new Set(['A', 'B', 'C']); for (const x of set.keys()) { console.log(x); } // A // B // C -
Set.prototype.values():返回键值的遍历器const set = new Set(['A', 'B', 'C']); for (const x of set.values()) { console.log(x); } // A // B // C -
Set.prototype.entries():返回键值对的遍历器for (let item of set.entries()) { console.log(item); } // ["A", "A"] // ["B", "B"] // ["C", "C"] -
Set.prototype.forEach():使用回调函数遍历每个成员forEach方法的参数是一个处理函数;该函数的参数与数组的forEach一致,依次为键值、键名、集合本身 与 第二个参数用于绑定处理函数内部的this对象;let set = new Set([1, 4, 9]); set.forEach((value, key) => console.log(key + ' : ' + value)) // 1 : 1 // 4 : 4 // 9 : 9
Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法
Set.prototype[Symbol.iterator] === Set.prototype.values
// true
因此可以省略values方法,直接用for...of循环遍历 Set
const set = new Set(['A', 'B', 'C']);
for (const x of set) {
console.log(x);
}
// A
// B
// C
Set 常用操作
使用展开运算符去除数组重复成员 :
const array = [1, 2, 3, 4, 3, 2]
const setArr = [...new Set(array)]
// setArr: [1, 2, 3, 4]
使用Array.from方法将Set 集合转为数组
const set = new Set([1, 2, 3, 4])
const setArr = Array.from(set)
// setArr: [1, 2, 3, 4]
使用Set搭配 join 去除字符串重复成员:
const str = 'asdwacawcas'
const setStr = [...new Set()].join('')
// 'asdwac'
Set 实现并集交集差集
初始化示例两个Set集合:
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
通过展开运算符实现 并集:
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
通过将Set集合转换为数组并运用其filter方法筛选实现 交集:
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
通过将Set集合转换为数组并运用其filter方法筛选实现 差集:
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}
Set实现规范
以下摘取自JavaScript高级程序设计第四版:
从各方面来看,Set 跟 Map 都很相似,只是 API 稍有调整;唯一需要强调的就是集合的 API 对自身的简单操作;很多开发者都喜欢使用 Set 操作,但需要手动实现:或者是子类化 Set,或者是定义一个实用函数库;要把两种方式合二为一,可以在子类上实现静态方法,然后在实例方法中使用这些静态方法;在实现这些操作时,需要考虑几个地方。
某些 Set 操作是有关联性的,因此最好让实现的方法能支持处理任意多个集合实例。
Set 保留插入顺序,所有方法返回的集合必须保证顺序。
尽可能高效地使用内存。扩展操作符的语法很简洁,但尽可能避免集合和数组间的相互转换能
够节省对象初始化成本
不要修改已有的集合实例
总结
Set是一个没有重复值的集合,默认可迭代,它没有键名,只有键值(迭代时键值相同);通常用于去重,可以轻松实现并集交集差集
最后如果本文对于本文有疑惑,还请指导勘正 (●'◡'●)