Map
ES6 新增了一种数据结构 Map,与传统的对象字面量类似,它的本质是一种键值对的组合。但是与对象字面量不同的是,对象字面量的键只能是字符串,对于非字符串类型的值会采用强制类型转换成字符串,而 Map 的键却可以由各种类型的值组成。
1 | // 传统的对象类型 |
在上面案例中,采用的是传统的对象处理方式,我们将对一个对象作为对象的键,在输出时会将所有的键如 xx 转换为字符串。所以我们得到字符串键 “[object Object]”。这显然不是我们想要的结果。
1 | let xx = {name: 'xx'} |
使用 Map 处理方法,将一个对象作为键添加到 map 实例中,在输出时发现,键的值为对象的真实值,并没有转换成字符串。
当创建一个 Map 后,我们可以传入一个带有键值对的数组(或其它可迭代对象)来进行初始化。
1 | let map = new Map([ |
Map 的属性和方法
- new Map() —— 创建 map。
- map.set(key, value) —— 根据键存储值。
- map.get(key) —— 根据键来返回值,如果 map 中不存在对应的 key,则返回 undefined。
- map.has(key) —— 如果 key 存在则返回 true,否则返回 false。
- map.delete(key) —— 删除指定键的值。
- map.clear() —— 清空 map。
- map.size —— 返回当前元素个数。
map[key] 不是使用 Map 的正确方式
虽然 map[key] 也有效,例如我们可以设置 map[key] = 23,这样会将 map 视为 JavaScript 的 plainobject,因此它暗含了所有相应的限制(没有对象键等)。
所以我们应该使用 map 方法:set 和 get 等。
在 Map 数据结构中,所有的键都必须具有唯一性。如果对同一个键进行多次赋值,那么后面的值会覆盖前面的值。
1 | let map = new Map() |
Map 是怎么比较键的?
Map 使用 SameValueZero 算法来比较键是否相等。它和严格等于 === 差不多,但区别是 NaN 被看成是等于 NaN。所以 NaN 也可以被用作键。
链式调用
每一次 map.set 调用都会返回 map 本身,所以我们可以进行“链式”调用:
map.set(‘name’, ‘xx1’).set(‘age’, 23)
Map 的遍历
- map.keys() —— 遍历并返回所有的键,
- map.values() —— 遍历并返回所有的值,
- map.entries() —— 遍历并返回所有的实体[key, value],for..of 在默认情况下使用的就是这个,
- map.forEach(item, key) —— 第一个参数表示值,第二个参数表示键。
1 | let map = new Map() |
map.entries === map[Symbol.iterator]
使用插入顺序
迭代的顺序与插入值的顺序相同。与普通的 Object 不同,Map 保留了此顺序。
Map 与其他数据类型的转换
数组转换成 Map
数组转换成 Map,可以通过 Map 构造函数实现,使用 new 操作符生成 Map 实例。
1 | let arr = [['name', 'xx'], ['age', 23]] |
Map 转换成数组
Map 转换成数组,可以通过扩展运算符实现。
1 | let map = new Map() |
对象转换成 Map
如果我们想从一个已有的普通对象来创建一个 Map,那么我们可以使用内建方法 Object.entries(obj),该方法返回对象的键/值对数组,该数组格式完全按照 Map 所需的格式。
1 | let obj = { |
Map 转换成对象
我们刚刚已经学习了如何使用 Object.entries(obj) 从普通对象创建 Map。
Object.fromEntries 方法的作用是相反的:给定一个具有 [key, value] 键值对的数组,它会根据给定数组创建一个对象。
1 | let map = new Map() |
Map 转换成 Json
当 Map 的键名都是字符串
当 Map 的键名都是字符串时,可以先将 Map 转换成对象,然后调用JSON.stringify()函数。
1 | let map = new Map() |
当 Map 的键名有非字符串
当 Map 的键名有非字符串时,我们可以先将 Map 转换成数组,然后调用JSON.stringify()函数
1 | let map = new Map() |