ES6提供了新的数据结构——Set。它类似于数组,但是成员的值都是唯一的,没有重复。Set本身是一个构造函数,用来生成Set数据结构。
const s = new Set();
[2,3,5,4,5,2,2].forEach(x=> s.add(x));
for(let i of s) {
console.log(i)
}
// 2,3,5,4
上面的代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。
Set函数可以接收一个数组(或者具有iterable接口的其他数据结构)作为参数,用来初始化。
例一:
const set = new Set([1,2,3,4,4])
[...set]
// [1,2,3,4]
例二:
const items= new Set([1,2,3,4,5,5,5,5]);
items.size // 5
向Set加入值时不会发生类型转换,所以 1 和 “1” 是两个不同的值。Set内部判断两个值是否相同时,使用的算法叫作“Same-value-equality”,它类似于精确相等运算符(===),主要的区别是NaN等于自身,而精确相等运算符中 NaN是不等于自身的。
let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set{ NaN }
上面的代码向Set实例添加了两个NaN,但实际上只能添加一个。这表明,在Set内部,两个NaN是相等的。
另外,两个对象总是不相等的。
let set = new Set();
set.add({});
set.size // 1
set.add({})
set.size // 2
Set结构的实例有以下属性。
Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍4个操作方法。
上面的属性和方法的实例如下:
let s = new Set()
s.add(1).add(2).add(2)
// 注意此时添加了两次2
s.size // 2
s.has(1) // true
s.has(2) // true
s.has(3) // false
s.delete(2)
s.has(2) // false
console.log(s)
下面是一个对比,判断是否包括一个键上的Object结构和Set结构的写法相同。
// 对象的写法
const properties = {
'width': 1,
'height': 1
}
if(properties[someName]) {
// do something
}
// Set的写法
const properties = new Set();
properties.add('width')
properties.add('height')
if(properties[someName]) {
// do something
}
// Array.from方法可以将Set结构转换为数组
const items = new Set([1,2,3,4,5]);
const array = Array.from(items);
这就提供了一种去除数组的重复元素的方法
function dedupe(array) {
return Array.from(new Set(array))
}
dedupe([1,2,3,4,5,5]) // [1,2,3,4,5]
Set结构的实例有4个遍历方法,可用于遍历成员。
需要特别指出的是,Set的遍历顺序就是插入顺序。
keys方法、values方法、entries方法返回的都是遍历器对象。由于Set结构没有键名,只有键值(或者说
键名与键值是同一个值),所以keys方法和values方法的行为是相同的
let set = new Set(['red', 'green', 'blue'])
for(let item of set.keys()) {
console.log(item)
}
// red
// green
// blue
for(let item of set.entries()) {
console.log(items)
}
// red
// green
// blue
for(let item of set.entries) {
console.log(item)
}
// ["red","red"]
// ["green","green"]
// ["blue","blue"]
上面的代码中,entries方法返回的遍历器同时包括键名和键值,所以每次输出一个数组,其两个成员完全相等。
Set结构的实例默认可遍历,其默认遍历器生成函数就是它的values方法。
// 对象的Symbol.iterator属性指向该对象的默认遍历器方法
Set.prototype[Symbol.iterator] === Set.prototype.values // true
这意味着,可以省略values方法,直接用for…of循环遍历Set。
let Set = new Set(['red', 'green', 'blue'])
for(let x of set) {
console.log(x)
}
// red
// green
// blue
forEach()
Set结构实例的forEach方法用于对每个成员执行某种操作,没有返回值。
let set = new Set([1,2,3])
set.forEach((value,key)=> console.log(value*2))
// 2
// 4
// 6
上面的代码说明,forEach方法的参数就是一个处理函数。该函数的参数依次为键值、键名、集合本身(上例省略了该参数)。另外,forEach方法还可以有第二个参数,表示绑定的this对象。
总结:Set本身是一个构造函数,接收的参数是一个数组或者可迭代的数据结构。生成的数据都是可迭代的数据对象且都不重复。可以通过Array.from()将set数据转成数组,或者用扩展运算符转换成数组。