Set集合数据结构。Set很多方面像是加强的Map,这是因为它们的大多数API和行为都是共享的。
基本API
const s = new Set();
// 使用数组初始化集合实例
const s1 = new Set(['val1', 'val2']);
alert(s1.size); // 2
// 使用自定义迭代器初始化集合
const s2 = new Set({
[Symbol.iterator]: function*() {
yield 'val1';
yield 'val2';
yoeld 'val3';
}
});
-
使用add()增加值
-
has():查询
-
size:size属性取得元素数量
-
delete():删除指定元素
-
clear():清空集合
-
add()返回集合的实例,所以可以将多个添加操作连缀起来,包括初始化。
-
与Map类似,Set可以包含任何JavaScript数据类型作为值。集合也使用SameValueZero操作(ECMAScript内部定义,无法在语言中使用),基本上相当于使用严格对象相等的标准来检查值的匹配性。
const s = new Set();
const functionVal = function() {};
const symbolVal = Symbol();
const objectVal = new Object();
s.add(functionVal).add(symbolVal).add(objectVal);
s.has(functionVal); // true
s.has(objectVal); // true
- 与严格相等一样,用作值得对象和其他集合类型在自己得内容或属性被修改时也不会改变:
const s = new Set();
const objVal = {}, arrVal = [];
s.add(objVal);
s.add(arrVal);
objVal.bar = "bar";
arrVal.push("bar");
alert(s.has(objVal)); // true
alert(s.has(arrVal)); // true
- add()和delete()操作都是幂等得。
- delete()返回一个布尔值,表示集合中是否存在要删除得值:
const s = new Set();
s.add('foo');
alert(s.size); // 1
a.add('foo');
alert(s.size); // 1
// Set中存在要删除的值
alert(s.delete('foo')); // true
// 否则
// false
顺序与迭代
- Set会维护值插入时的顺序因此支持顺序迭代。
- Set实例可以提供一个迭代器Iterator,能以插入顺序生成集合内容。可以通过values()方法及其别名方法keys()(或Symbol.iterator属性,它引用values())取得这个迭代器:
const s = new Set(['val1', 'val2', 'val3']);
alert(s.values === s[Symbol.iterator]); // true
alert(s.keys === s[Symbol.iterator]); // true
for (let value of s.values()) {
alert(value)
};
for (let value of s[Symbol.iterator]()) {
alert(value)
}
- values()是默认迭代器,所以可以直接对集合实例使用扩展操作,把集合转换为数组:
const s = new Set(['val1', 'val2', 'val3']);
[...s]; // ['val1', 'val2', 'val3']
- 集合的entries()方法返回一个迭代器,可以按照插入顺序产生包含两个元素的数组,这两个元素是集合中每个值的重复出现.
for (let pair of s.entries()) {}
- 使用回调函数,可以调用集合的forEach()方法并传入回调,依次迭代每个键值对。
s.forEach((val, dupVal) => alert(`${val} -> ${dupVal}`));
- 修改集合中值的属性不会影响其作为集合值的身份。
定义正式集合操作
-
Set与Map相似,只是API稍有调整。唯一需要强调的就是集合的API对自身的简单操作。
-
很多开发者都喜欢使用Set操作,但需要手动实现:或者是子类化Set,或者是定义一个实用函数库。要把两种方式合二为一,可以在子类上实现静态方法,然后在实例方法中使用这些静态方法。在实现这些操作时,需要考虑几个地方。
- 某些Set操作是有关联性的,因此最好让实现的方法能支持处理任意多个集合实例
- Set保留插入顺序,所有方法返回的集合必须保证顺序。
- 尽可能高效地使用内存。扩展操作符的语法很简洁,但尽可能避免集合和数组间的相互转换能够节省对象初始化成本。
- 不要修改已有的集合实例。union(a, b)或a.union(b)应该返回包含结果的新集合实例。