在做算法题的过程中,发现当用数字作为一个对象的键来存储数据时,后续取对象中的数据,并不会根据你存入的顺序取出数据。

由此判断出对象中的键其实不是无序的,这个时候可以使用 Map 数据结构来代替。

一、Map 介绍

Map 和 Object 一样用来存取键值对形式的数据。不过 Object 可以使用字面量和构造函数两种方式创建,而 Map 结构必须使用构造函数创建。如下所示:

1
2
3
4
5
6
7
8
9
10
// 创建一个空的Map对象
const mapOne = new Map()

// 创建一个Map对象并赋初值,参数必须是一个数组(或iterable对象)。
// 其元素为键值对(两个元素的数组,例如: [[ 1, 'one' ],[ 2, 'two' ]])。 每个键值对都会添加到新的 Map
const mapTwo = new Map([
[1, 'one'],
[true, 'two'],
[{ a: '1' }, 'three'],
])

正如上述第二种方式创建 Map,Map 的键可以为任意数据结构。

二、Map 和 Object 的对比

Map Object
创建方式 const myMap = new Map() const obj = {}const myObj = new Object()
键的类型 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。 一个Object 的键必须是一个 String或是Symbol
键的顺序 Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 一个 Object 的键是无序的
获取一个键(key)的值 let value = myMap.get(key) let value = obj.keylet value = obj[key]
往对象中新增一个键值对 myMap.set(key, value) obj.key = valueobj[key] = value
删除对象中的键值对 myMap.delete(key) delete obj.keydelete obj[key]
对象的 Size let size = myMap.size let size = 0; for (const key in obj) { size++ }
遍历对象 可直接用 forEach、for、forin、forof 进行遍历 只能用 forin 进行遍历
性能 在频繁增删键值对的场景下表现更好。 在频繁添加和删除键值对的场景下未作出优化。

三、本次使用的场景

在算法题中,我需要用一个对象来存储一个整数数组中元素为键,出现的次数为值。

1
2
3
4
5
6
7
8
// 例如:
arr = [3, 3, 3, 1, 2, 1, 1, 2]
// 存储为
obj = {
3: 3,
1: 3,
2: 2,
}

这里有另一个需求是,我后续需要根据存进对象的顺序来移除键值对,又因为这里的键是数字,JS 运行环境中,默认又重新根据数字的大小排列了对象,如下图,于是很难根据存入的顺序来进行删除,这时就可以使用 Map 结构

image-20210622232356850

使用 Map 存储该内容后,结果如下:

image-20210622232716729

四、推荐使用 Map 的场景

  1. 在存取对象时,需要有序的情况下,最好使用 Map
  2. 在需要频繁增删对象中的键值对时,最好使用 Map