Set
)a
∪ b
)a
∩ b
)a
\ b
)Set<T>
Set<T>.prototype
:单个集合元素Set<T>.prototype
:所有集合元素Set<T>.prototype
:迭代和循环Map
的对称性.size
,而数组有 .length
?在 ES6 之前,JavaScript 没有用于集合的数据结构。相反,使用了两种变通方法
从 ES6 开始,JavaScript 拥有数据结构 Set
,它可以包含任意值并快速执行成员资格检查。
创建集合有三种常用方法。
首先,您可以使用不带任何参数的构造函数来创建一个空集合
const emptySet = new Set();
.equal(emptySet.size, 0); assert
其次,您可以将可迭代对象(例如,数组)传递给构造函数。迭代值将成为新集合的元素
const set = new Set(['red', 'green', 'blue']);
第三,.add()
方法将元素添加到集合中,并且可以链接
const set = new Set()
.add('red')
.add('green')
.add('blue');
.add()
将元素添加到集合中。
const set = new Set();
.add('red'); set
.has()
检查元素是否是集合的成员。
.equal(set.has('red'), true); assert
.delete()
从集合中删除元素。
.equal(set.delete('red'), true); // there was a deletion
assert.equal(set.has('red'), false); assert
.size
包含集合中元素的数量。
const set = new Set()
.add('foo')
.add('bar');
.equal(set.size, 2) assert
.clear()
删除集合中的所有元素。
.clear();
set.equal(set.size, 0) assert
集合是可迭代的,for-of
循环按预期工作
const set = new Set(['red', 'green', 'blue']);
for (const x of set) {
console.log(x);
}// Output:
// 'red'
// 'green'
// 'blue'
如您所见,集合保留*插入顺序*。也就是说,始终按照添加元素的顺序迭代元素。
鉴于集合是可迭代的,您可以使用 Array.from()
将它们转换为数组
const set = new Set(['red', 'green', 'blue']);
const arr = Array.from(set); // ['red', 'green', 'blue']
将数组转换为集合并转换回来,可以删除数组中的重复项
.deepEqual(
assertArray.from(new Set([1, 2, 1, 2, 3, 3, 3])),
1, 2, 3]); [
字符串是可迭代的,因此可以用作 new Set()
的参数
.deepEqual(
assertnew Set('abc'),
new Set(['a', 'b', 'c']));
与 Map 键一样,集合元素的比较方式类似于 ===
,但 NaN
等于自身除外。
> const set = new Set([NaN, NaN, NaN]);
> set.size1
> set.has(NaN)true
与 ===
一样,两个不同的对象永远不会被认为是相等的(目前无法改变这一点)
> const set = new Set();
> set.add({});
> set.size1
> set.add({});
> set.size2
集合缺少几种常见操作。此类操作通常可以通过以下方式实现
a
∪ b
)计算两个集合 a
和 b
的并集意味着创建一个包含 a
和 b
中所有元素的集合。
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]);
.deepEqual(Array.from(union), [1, 2, 3, 4]); assert
a
∩ b
)计算两个集合 a
和 b
的交集意味着创建一个包含 a
中也存在于 b
中的元素的集合。
const a = new Set([1,2,3]);
const b = new Set([4,3,2]);
const intersection = new Set(
Array.from(a).filter(x => b.has(x))
;
)
.deepEqual(
assertArray.from(intersection), [2, 3]
; )
a
\ b
)计算两个集合 a
和 b
的差集意味着创建一个包含 a
中不存在于 b
中的元素的集合。此操作有时也称为*减* (−)。
const a = new Set([1,2,3]);
const b = new Set([4,3,2]);
const difference = new Set(
Array.from(a).filter(x => !b.has(x))
;
)
.deepEqual(
assertArray.from(difference), [1]
; )
集合没有 .map()
方法。但我们可以借用数组的方法
const set = new Set([1, 2, 3]);
const mappedSet = new Set(
Array.from(set).map(x => x * 2)
;
)
// Convert mappedSet to an Array to check what’s inside it
.deepEqual(
assertArray.from(mappedSet), [2, 4, 6]
; )
我们不能直接对集合使用 .filter()
,因此我们需要使用相应的数组方法
const set = new Set([1, 2, 3, 4, 5]);
const filteredSet = new Set(
Array.from(set).filter(x => (x % 2) === 0)
;
)
.deepEqual(
assertArray.from(filteredSet), [2, 4]
; )
Set<T>
new Set<T>(values?: Iterable<T>)
[ES6]
如果您不提供参数 values
,则会创建一个空集合。如果提供,则迭代值将作为元素添加到集合中。例如
const set = new Set(['red', 'green', 'blue']);
Set<T>.prototype
:单个集合元素.add(value: T): this
[ES6]
将 value
添加到此集合中。此方法返回 this
,这意味着它可以链接。
const set = new Set(['red']);
.add('green').add('blue');
set.deepEqual(
assertArray.from(set), ['red', 'green', 'blue']
; )
.delete(value: T): boolean
[ES6]
从此集合中删除 value
。如果删除了内容,则返回 true
,否则返回 false
。
const set = new Set(['red', 'green', 'blue']);
.equal(set.delete('red'), true); // there was a deletion
assert.deepEqual(
assertArray.from(set), ['green', 'blue']
; )
.has(value: T): boolean
[ES6]
检查 value
是否在此集合中。
const set = new Set(['red', 'green']);
.equal(set.has('red'), true);
assert.equal(set.has('blue'), false); assert
Set<T>.prototype
:所有集合元素get .size: number
[ES6]
返回此集合中的元素数量。
const set = new Set(['red', 'green', 'blue']);
.equal(set.size, 3); assert
.clear(): void
[ES6]
从此集合中删除所有元素。
const set = new Set(['red', 'green', 'blue']);
.equal(set.size, 3);
assert.clear();
set.equal(set.size, 0); assert
Set<T>.prototype
:迭代和循环.values(): Iterable<T>
[ES6]
返回此集合中所有元素的可迭代对象。
const set = new Set(['red', 'green']);
for (const x of set.values()) {
console.log(x);
}// Output:
// 'red'
// 'green'
[Symbol.iterator](): Iterable<T>
[ES6]
迭代集合的默认方式。与 .values()
相同。
const set = new Set(['red', 'green']);
for (const x of set) {
console.log(x);
}// Output:
// 'red'
// 'green'
.forEach(callback: (value: T, key: T, theSet: Set<T>) => void, thisArg?: any): void
[ES6]
将此集合中的每个元素提供给 callback()
。value
和 key
都包含当前元素。引入这种冗余是为了使此 callback
具有与 Map.prototype.forEach()
的 callback
相同的类型签名。
您可以通过 thisArg
指定 callback
的 this
。如果省略它,则 this
为 undefined
。
const set = new Set(['red', 'green']);
.forEach(x => console.log(x));
set// Output:
// 'red'
// 'green'
Map
的对称性以下两种方法主要存在是为了使集合和映射具有相似的接口。每个集合元素都被视为其键和值都是该元素的 Map 条目。
Set.prototype.entries(): Iterable<[T,T]>
[ES6]Set.prototype.keys(): Iterable<T>
[ES6].entries()
使您能够将集合转换为映射
const set = new Set(['a', 'b', 'c']);
const map = new Map(set.entries());
.deepEqual(
assertArray.from(map.entries()),
'a','a'], ['b','b'], ['c','c']]
[[; )
.size
,而数组有 .length
?这个问题的答案在 §33.6.4 “为什么映射有 .size
,而数组有 .length
?” 中给出。
测验
参见 测验应用程序。