32.集(Set)
在 ES6 之前,JavaScript 没有集合的数据结构。相反,使用了两种解决方法:
- 对象的键作为字符串集。
- 数组作为任意值的集合(例如,通过
.includes()
检查元素是否在集合中)。
ECMAScript 6 具有数据结构Set
,适用于任意值。
32.1。使用集合
32.1.1。创建集
创建集合有三种常用方法。
首先,您可以使用不带任何参数的构造函数来创建空集:
const emptySet = new Set();
assert.equal(emptySet.size, 0);
其次,您可以将迭代(例如,数组)传递给构造函数。迭代值成为新集的元素:
const set = new Set(['red', 'green', 'blue']);
第三,.add()
方法将元素添加到 Set 并且是可链接的:
const set = new Set()
.add('red')
.add('green')
.add('blue');
32.1.2。添加,删除,检查包含
.add()
向 Set 添加元素。 .has()
检查某个元素是否包含在一个集合中。 .delete()
从 Set 中删除元素。
const set = new Set();
set.add('red');
assert.equal(set.has('red'), true);
assert.equal(set.delete('red'), true); // there was a deletion
assert.equal(set.has('red'), false);
32.1.3。确定 Set 的大小并清除它
.size
包含 Set 中的元素数。 .clear()
删除 Set 的所有元素。
const set = new Set()
.add('foo')
.add('bar')
;
assert.equal(set.size, 2)
set.clear();
assert.equal(set.size, 0)
32.1.4。迭代一组
集是可迭代的,for-of
循环按预期工作:
const set = new Set(['red', 'green', 'blue']);
for (const x of set) {
console.log(x);
}
// Output:
// 'red'
// 'green'
// 'blue'
如您所见,集合保留迭代顺序。也就是说,元素总是按照添加顺序迭代。
Spreading(...
)到数组可以与 iterables 一起使用,因此可以将 Set 转换为数组:
const set = new Set(['red', 'green', 'blue']);
const arr = [...set]; // ['red', 'green', 'blue']
32.1.4.1。从数组和字符串中删除重复项
将数组转换为 Set 并返回,从数组中删除重复项:
assert.deepEqual(
[...new Set([1, 2, 1, 2, 3, 3, 3])],
[1, 2, 3]);
字符串也是可迭代的,因此可以用作new Set()
的参数:
assert.equal(
[...new Set('ababccc')].join(''),
'abc');
32.2。比较 Set 元素
与 Maps 一样,元素与===
类似地进行比较,但NaN
等于它自身。
> const set = new Set([NaN]);
> set.size
1
> set.has(NaN)
true
第二次添加元素无效:
> const set = new Set();
> set.add('foo');
> set.size
1
> set.add('foo');
> set.size
1
与===
类似,两个不同的对象永远不会被认为是相同的(目前无法自定义):
> const set = new Set();
> set.add({});
> set.size
1
> set.add({});
> set.size
2
32.3。缺少 Set 操作
集合缺少几个常见操作。它们通常可通过以下方式实施:
- 将集转换为数组(通过传播(
...
))。 - 执行操作。
- 将结果转换回 Set。
32.3.1。制图
const set = new Set([1, 2, 3]);
const mappedSet = new Set([...set].map(x => x * 2));
// Convert mappedSet to an Array to check what’s inside it
assert.deepEqual([...mappedSet], [2, 4, 6]);
32.3.2。过滤
const set = new Set([1, 2, 3, 4, 5]);
const filteredSet = new Set([...set].filter(x => (x % 2) === 0));
assert.deepEqual([...filteredSet], [2, 4]);
32.3.3。联盟
Union(a
∪b
):创建一个包含 Set a
和 Set b
元素的 Set。
const a = new Set([1,2,3]);
const b = new Set([4,3,2]);
// Use spreading to concatenate two iterables
const union = new Set([...a, ...b]);
assert.deepEqual([...union], [1, 2, 3, 4]);
32.3.4。路口
交点(a
∩b
):创建一个包含 Set a
元素的 Set,它们也在 Set b
中。
const a = new Set([1,2,3]);
const b = new Set([4,3,2]);
const intersection = new Set(
[...a].filter(x => b.has(x)));
assert.deepEqual([...intersection], [2, 3]);
32.3.5。区别
差值(a
\ b
):创建一个包含 Set a
中不在 Set b
中的元素的 Set。该操作有时也称为 _ 减去 _(-
)。
const a = new Set([1,2,3]);
const b = new Set([4,3,2]);
const difference = new Set(
[...a].filter(x => !b.has(x)));
assert.deepEqual([...difference], [1]);
32.4。快速参考:Set<T>
32.4.1。构造函数
new Set<T>(values?: Iterable<T>)
[ES6]如果未提供参数
values
,则会创建一个空集。如果这样做,则迭代值将作为元素添加到 Set 中。例如:const set = new Set(['red', 'green', 'blue']);
32.4.2。 Set<T>.prototype
:单个设置元素
.add(value: T): this
[ES6]将
value
添加到此 Set。此方法返回this
,这意味着它可以链接。const set = new Set(['red', 'green']); set.add('blue'); assert.deepEqual([...set], ['red', 'green', 'blue']);
.delete(value: T): boolean
[ES6]从此 Set 中删除
value
。const set = new Set(['red', 'green', 'blue']); assert.equal(set.delete('red'), true); // there was a deletion assert.deepEqual([...set], ['green', 'blue']);
.has(value: T): boolean
[ES6]检查
value
是否在此设置中。const set = new Set(['red', 'green']); assert.equal(set.has('red'), true); assert.equal(set.has('blue'), false);
32.4.3。 Set<T>.prototype
:所有 Set 元素
get .size: number
[ES6]返回此 Set 中有多少元素。
const set = new Set(['red', 'green', 'blue']); assert.equal(set.size, 3);
.clear(): void
[ES6]从此 Set 中删除所有元素。
const set = new Set(['red', 'green', 'blue']); assert.equal(set.size, 3); set.clear(); assert.equal(set.size, 0);
32.4.4。 Set<T>.prototype
:迭代和循环
.values(): Iterable<T>
[ES6]返回此 Set 的所有元素的可迭代。
const set = new Set(['red', 'green']); for (const x of set.values()) { console.log(x); } // Output: // 'red' // 'green'
[Symbol.iterator](): Iterable<T>
[ES6]迭代 Set 的默认方式。与
.values()
相同。const set = new Set(['red', 'green']); for (const x of set) { console.log(x); } // Output: // 'red' // 'green'
.forEach(callback: (value: T, value2: T, theSet: Set<T>) => void, thisArg?: any): void
[ES6]循环遍历此 Set 的元素,并为每个元素调用回调(第一个参数)。
value
和key
都设置为元素,因此该方法与Map.prototype.forEach
的工作方式类似。如果提供了thisArg
,则为每个呼叫设置this
。否则,this
设置为undefined
。const set = new Set(['red', 'green']); set.forEach(x => console.log(x)); // Output: // 'red' // 'green'
32.4.5。与Map
对称
仅存在以下两种方法,以使 Sets 的接口类似于 Maps 的接口。处理每个 Set 元素就好像它是一个 Map 键,其键和值是元素。
Set.prototype.entries(): Iterable<[T,T]>
[ES6]Set.prototype.keys(): Iterable<T>
[ES6]
.entries()
使您可以将 Set 转换为 Map:
const set = new Set(['a', 'b', 'c']);
const map = new Map(set.entries());
assert.deepEqual(
[...map.entries()],
[['a','a'], ['b','b'], ['c','c']]);
参见测验应用程序。