Map Set Generators

最近沉迷于生成器(Generator)、迭代器(Iterator)不能自拔,感觉真的很有意思,今天偶然间发现Map集合、Set集合跟竟然它们也有关系!

◎ 😂

先从数组去重说起,几乎每一篇关于「数组去重」的文章里面都会有下面这种利用Set集合的方式来去重的:

1
const unique = array => [...new Set(array)];

...叫做展开运算符,可是你有想过,为什么它可以展开Set集合吗?是因为Set集合特别香?它还可以展开Map集合、数组你知道吗?甚至是字符串!

1
[...'Tim'] // ['T', 'i', 'm'];

既然展开运算符可以作用到他们的身上,那么他们一定有一个共同点!该去哪里找共同点呢?我脑海中灵光一闪,原型(prototype)!一定是原型,于是我尝试在控制台里分别输出 Array.prototype、Map.prototype、Set.prototype、String.prototype来对比着看,还真让我找到了,他们竟然都有一个属性,Symbol.iterator!!而当我使用typeof操作符来查看这个属性值的类型时,一切都很清晰了:

1
typeof Map.prototype[Symbol.iterator] // function

我们管拥有Symbol.iterator属性的对象叫做可迭代对象,简单理解的话就是他们可以被迭代😂。当展开运算符或者for...of作用于这些可迭代对象时,会访问他们Symbol.iterator属性,然后调用这个属性,生成一个迭代器。之后的过程当然就是不停地调用迭代器的next方法,直到next方法返回的结果对象的done属性为true时才停止。

事情并没有结束,Map集合它拥有三个内置的迭代器,entries、keys、values。默认的迭代器是entries,所以Map的Symbol.iterator属性指向entries属性。

1
Map.prototype[Symbol.iterator] === Map.prototype.entries; // true

我们可以顺便看看Map集合的这几个默认的迭代器都返回什么:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const map = new Map([['age', 18], ['name', 'Tim']]);

for(const item of map.entries()) {
	console.log(item);
}
// [['age', 18]]
// ['name', 'Tim']

for(const item of map.keys()) {
	console.log(item);
}
// age
// name

for(const item of map.values()) {
	console.log(item);
}
// 18
// Tim

Set集合和数组也都拥有这三个内置的迭代器,并且他们的默认迭代器都是values,也就是说:

1
2
Set.prototype[Symbol.iterator] === Set.prototype.values; // true
Array.prototype[Symbol.iterator] === Array.prototype.values; // true

Set集合由于它没有key,它只是不重复的元素列表,所以Set的keys和values为同一个函数:

1
Set.prototype.keys === Set.prototype.values; // true

至于数组、Set集合的三个内置的迭代器的展开形式就不在此一一列举了,这篇文章的主要目的是想说明迭代器与生成器已经在JS中处处可见了,我们常用的展开运算符、for...of都在底层使用他们。肯定会有杠精抬杠说,了解这些有什么用吗?

◎ 😂

updatedupdated2020-07-062020-07-06