30.映射(Map
)
在 ES6 之前,JavaScript 没有字典的数据结构和(ab)使用的对象作为从字符串到任意值的字典。 ES6 带来了映射,这些映射是从任意值到任意值的字典。
30.1。使用映射
Map
的实例将键映射到值。单个键值映射称为 条目 。映射记录创建订单条目并在返回时遵守该订单,例如密钥或条目。
30.1.1。创建映射
创建映射有三种常用方法。
首先,您可以使用不带任何参数的构造函数来创建空 Map:
其次,您可以通过键值“对”(具有 2 个元素的数组)将可迭代(例如数组)传递给构造函数:
第三,.set()
方法向 Map 添加条目并且是可链接的:
30.1.2。使用单个条目
.set()
和.get()
用于写入和读取值(给定键)。
.has()
检查 Map 是否具有给定键的条目。 .delete()
删除条目。
30.1.3。确定映射的大小并清除它
.size
包含 Map 中的条目数。 .clear()
删除 Map 的所有条目。
30.1.4。获取映射的键和值
.keys()
在 Map 的键上返回一个 iterable:
我们可以使用 spread(...
)将.keys()
返回的可迭代转换为数组:
.values()
的作用类似于.keys()
,但是对于值而不是键。
30.1.5。获取映射的条目
.entries()
在 Map 的条目上返回一个 iterable:
Spreading(...
)将.entries()
返回的可迭代转换为数组:
映射实例也是条目上的迭代。在下面的代码中,我们使用解构来访问map
的键和值:
30.2。示例:计算字符数
countChars()
返回将字符映射到出现次数的 Map。
30.3。关于映射键的更多细节(高级)
任何值都可以是键,甚至是对象:
30.3.1。什么键被认为是平等的?
大多数 Map 操作需要检查值是否等于其中一个键。它们是通过内部操作 SameValueZero 来实现的,它的作用类似于===
,但认为NaN
等于它自己。
因此,您可以在映射中使用NaN
作为键,就像任何其他值一样:
不同的对象总是被认为是不同的。这是无法配置的东西(但是 - TC39 意识到这是重要的功能)。
30.4。缺少映射操作
30.4.1。映射和过滤映射
你可以.map()
和.filter()
数组,但映射没有这样的操作。解决方案是:
- 将 Map 转换为[key,value]对数组。
- 映射或过滤数组。
- 将结果转换回 Map。
我将使用以下 Map 来演示它是如何工作的。
映射originalMap
:
过滤originalMap
:
步骤 1 由扩展运算符(...
)执行。
30.4.2。结合映射
没有组合映射的方法,这就是为什么必须使用上一节的方法来实现这一点。
让我们结合以下两个映射:
要组合map1
和map2
,我们通过扩展运算符(...
)将它们转换为数组并连接这些数组。然后,我们将结果转换回 Map。所有这一切都在 A 行完成。
练习:结合两张映射
exercises/maps-sets/combine_maps_test.js
30.5。快速参考:Map<K,V>
注意:为了简洁起见,我假装所有键具有相同的类型K
并且所有值具有相同的类型V
。
30.5.1。构造函数
new Map<K, V>(entries?: Iterable<[K, V]>)
[ES6]如果未提供参数
entries
,则会创建空 Map。如果确实提供了[key,value]对的可迭代对,那么这些对用于向 Map 添加条目。例如:
30.5.2。 Map<K,V>.prototype
:处理单个条目
.get(key: K): V
[ES6]返回
key
在此 Map 中映射到的value
。如果此 Map 中没有键key
,则返回undefined
。.set(key: K, value: V): this
[ES6]将给定键映射到给定值。如果已存在其键为
key
的条目,则会更新该条目。否则,将创建一个新条目。此方法返回this
,这意味着您可以链接它。.has(key: K): boolean
[ES6]返回此 Map 中是否存在给定键。
.delete(key: K): boolean
[ES6]如果存在其键为
key
的条目,则将其删除并返回true
。否则,没有任何反应,并返回false
。
30.5.3。 Map<K,V>.prototype
:处理所有条目
get .size: number
[ES6]返回此 Map 中有多少条目。
在 JavaScript 中,可索引序列(例如 Arrays)具有
.length
,而主要是无序集合(例如 Maps)具有.size
。.clear(): void
[ES6]从此 Map 中删除所有条目。
30.5.4。 Map<K,V>.prototype
:迭代和循环
迭代和循环都按照将条目添加到 Map 的顺序发生。
.entries(): Iterable<[K,V]>
[ES6]为此 Map 中的每个条目返回一个具有一个[key,value]对的 iterable。这些对是长度为 2 的数组。
.forEach(callback: (value: V, key: K, theMap: Map<K,V>) => void, thisArg?: any): void
[ES6]第一个参数是为此 Map 中的每个条目调用一次的回调。如果提供了
thisArg
,则为每次调用设置this
。否则,this
设置为undefined
。.keys(): Iterable<K>
[ES6]返回此 Map 中所有键的可迭代。
.values(): Iterable<V>
[ES6]返回此 Map 中所有值的可迭代值。
[Symbol.iterator](): Iterable<[K,V]>
[ES6]迭代映射的默认方式。与
.entries()
相同。
30.5.5。来源
30.6。常问问题
30.6.1。什么时候我应该使用 Map,当一个对象?
如果将除字符串以外的任何内容映射到任何类型的数据,则别无选择:必须使用 Map。
但是,如果要将字符串映射到任意数据,则必须决定是否使用对象。粗略的一般准则是:
是否有一组固定的密钥(在开发时已知)?
然后使用一个对象并通过固定键访问这些值:obj.key
键组可以在运行时更改吗?
然后使用 Map 并通过存储在变量中的键访问值:map.get(theKey)
30.6.2。我何时将对象用作映射中的键?
如果通过值比较映射键主要是有意义的(相同的“内容”意味着两个值被认为是相同的,而不是相同的身份)。这排除了对象。有一个用例 - 外部将数据附加到对象,但 WeakMaps 更好地服务于用例,其中条目不会阻止垃圾收集(有关详细信息,请参阅下一章)。
测验
参见测验应用程序。