ES6之Set数据结构

402 阅读3分钟

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

ECMAScript 6 新增的 Set 是一种新集合类型,为这门语言带来集合数据结构。Set 在很多方面都像是加强的 Map,这是因为它们的大多数 API 和行为都是共有的

使用 new 关键字和 Set 构造函数可以创建一个空集合:

const m = new Set();

如果想在创建的同时初始化实例,则可以给 Set 构造函数传入一个可迭代对象,其中需要包含插入到新集合实例中的元素:

// 使用数组初始化集合
const s1 = new Set(["val1", "val2", "val3"]);
alert(s1.size); // 3

// 使用自定义迭代器初始化集合
const s2 = new Set({
[Symbol.iterator]: function*() {
yield "val1";
yield "val2";
yield "val3";
}
});
alert(s2.size); // 3

Set用于存储任何类型的唯一值,无论是基本类型还是对象引用。

  • 只能保存值没有键名
  • 严格类型检测如字符串数字不等于数值型数字
  • 值是唯一的
  • 遍历顺序是添加的顺序,方便保存回调函数

基本API

初始化之后,可以使用add()增加值,使用 has()查询,通过 size 取得元素数量,以及使用 delete()clear()删除元素:

const s = new Set();
alert(s.has("Matt")); // false
alert(s.size); // 0

s.add("Matt")
 .add("Frisbie");
alert(s.has("Matt")); // true
alert(s.size); // 2

s.delete("Matt");
alert(s.has("Matt")); // false
alert(s.has("Frisbie")); // true
alert(s.size); // 1

s.clear(); // 销毁集合实例中的所有值
alert(s.has("Matt")); // false
alert(s.has("Frisbie")); // false
alert(s.size); // 0

add()返回集合的实例,所以可以将多个添加操作连缀起来,包括初始化:

const s = new Set().add("val1");
s.add("val2")
 .add("val3");
alert(s.size); // 3

注意对象的属性最终都会转为字符串

let obj = { 1: "qdxx", "1": "xiaoyiya" };
console.table(obj); //{1:"小亦呀"}

所以使用对象做为键名时,会将对象转为字符串后使用

let obj = { 1: "qdxx", "1": "xiaoyiya" };
    console.table(obj);   // {1:"小亦呀"}

let hd = { [obj]: "小亦呀" };
    console.table(hd);      //{[object Object]: "小亦呀"}

console.log(hd[obj.toString()]);   // 小亦呀
console.log(hd["[object Object]"]); // 小亦呀

与 Map 类似,Set 可以包含任何 JavaScript 数据类型作为值。集合也使用 SameValueZero 操作(ECMAScript 内部定义,无法在语言中使用),基本上相当于使用严格对象相等的标准来检查值的匹配性 也就是Set 中是严格类型约束的,下面的数值1与字符串1属于两个不同的值

let set = new Set();
set.add(1);
set.add("1");
console.log(set); //Set(2) {1, "1"}

一些很好的使用场景

数组转换

可以使用点语法 或 Array.form 静态方法将Set类型转为数组,这样就可以使用数组处理函数了

const set = new Set(["qdxx", "xiaoyiya"]);
console.log([...set]); //["qdxx", "xiaoyiya"]
console.log(Array.from(set)); //["qdxx", "xiaoyiya"]

移除Set中大于5的数值

let hd = new Set("123456789");
hd = new Set([...hd].filter(item => item < 5));
console.log(hd);

去除重复

去除字符串重复

console.log([...new Set("xiaoyiya")].join(""));//xiaoy

去除数组重复

const arr = [1, 2, 3, 5, 2, 3];
console.log(...new Set(arr)); // 1,2,4,5

遍历数据

使用 keys()/values()/entries() 都可以返回迭代对象(到这里,我们应该能看出Map和Set的很多相似之处和不同点),因为set类型只有值所以 keys与values 方法结果一致。

const hd = new Set(["qdxx", "xiaoyiya"]);
console.log(hd.values()); //SetIterator {"qdxx", "xiaoyiya"}
console.log(hd.keys()); //SetIterator {"qdxx", "xiaoyiya"}
console.log(hd.entries()); //SetIterator {"qdxx" => "qdxx", "xiaoyiya" => "xiaoyiya"}

可以使用 forEach 遍历Set数据,默认使用 values 方法创建迭代器。

为了保持和遍历数组参数统一,函数中的value与key是一样的。

let arr = [7, 6, 2, 8, 2, 6];
let set = new Set(arr);
//使用forEach遍历
set.forEach((item,key) => console.log(item,key));

也可以使用 for of 遍历Set数据,默认使用 values 方法创建迭代器

//使用for/of遍历
let set = new Set([7, 6, 2, 8, 2, 6]);

for (const iterator of set) {
	console.log(iterator);
}

交集

获取两个集合中共同存在的元素

let hd = new Set(['qdxx', 'xiaoyiya']);
let cms = new Set(['前端学习', 'qdxx']);
let newSet = new Set(
	[...hd].filter(item => cms.has(item))
);
console.log(newSet); //{"qdxx"}

差集

在集合a中出现但不在集合b中出现元素集合

let hd = new Set(['qdxx', 'xiaoyiya']);
let cms = new Set(['前端学习', 'qdxx']);
let newSet = new Set(
	[...hd].filter(item => !cms.has(item))
);
console.log(newSet); //{"xiaoyiya"}

并集

将两个集合合并成一个新的集合,由于Set特性当然也不会产生重复元素。

et hd = new Set(['qdxx', 'xiaoyiya']);
let cms = new Set(['前端学习', 'qdxx']);
let newSet = new Set([...hd, ...cms]);
console.log(newSet); // ["qdxx","xiaoyiya","前端学习"]