在 JavaScript 中,普通对象和 ES6 的新对象 Map 都可以存储键值对,平时普通对象用的较多,现在着重了解一下Map
描述
Map 对象存有键值对,其中的键可以是任何数据类型。
Map 对象记得键的原始插入顺序。
Map 对象具有表示映射大小的属性。
创建
构造函数创建
Iterable 可以是一个数组或者其他 iterable 对象,其元素为键值对(两个元素的数组,例如: [[ 1, ‘one’ ],[ 2, ‘two’ ]])。 每个键值对都会添加到新的 Map。null 会被当做 undefined。
方法和属性
打印map可得
size
访问属性,用于返回 一个Map 对象的成员数量。
has()
返回一个bool值,用来表明map 中是否存在指定元素,返回布尔值
set()
为 Map 对象添加或更新一个指定了键(key)和值(value)的(新)键值对
get()
返回某个 Map 对象中的一个指定元素。
keys()
返回一个引用的 Iterator 对象。它包含按照顺序插入 Map 对象中每个元素的key值
values()
返回一个新的Iterator对象。它包含按顺序插入Map对象中每个元素的value值。
entries()
返回一个新的包含 [key, value] 对的 Iterator 对象,返回的迭代器的迭代顺序与 Map 对象的插入顺序相同。
- next() 是Iterator 对象的方法
clear()
移除Map对象中的所有元素
delete()
移除 Map 对象中指定的元素,返回布尔值
forEach()
按照插入顺序依次对 Map 中每个键/值对执行一次给定的函数
for…of…
Map可以使用for..of循环来实现迭代
利用散布运算符…遍历集合
和普通对象的区别
Objects 和 Maps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。
不同的是:
1. 默认值
- Map 默认情况不包含任何键。只包含显式插入的键。
- 一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
2. 键类型
- 一个Object 的键必须是一个 String 或是Symbol。
- 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。
3. 键顺序
- 一个 Object 的键是无序的
- Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。
4. Size
- Object 的键值对个数只能手动计算
- Map 的键值对个数可以轻易地通过size 属性获取
5. 迭代
- 迭代一个Object需要以某种方式获取它的键然后才能迭代
- 使用 for…of 语句或 Map.prototype.forEach 直接迭代 Map 的属性
序列化和解析
- 普通对象支持 JSON 序列化
- Map 默认无法获取正确数据
性能
- 在频繁增删键值对的场景下表现更好
- 在频繁添加和删除键值对的场景下未作出优化
迭代协议:
迭代协议具体分为两个协议:可迭代协议和 迭代器协议。
可迭代协议:允许 JavaScript 对象定义或定制它们的迭代行为,例如,在一个 for..of 结构中,哪些值可以被遍历到。一些内置类型同时是内置可迭代对象,并且有默认的迭代行为,比如 Array 或者 Map,而其他内置类型则不是(比如 Object))
要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性:
属性 | 值 |
---|---|
[Symbol.iterator] | 一个无参数的函数,其返回值为一个符合迭代器协议的对象。 |
迭代器协议:定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值
只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才能成为迭代器:
属性 | 值 |
---|---|
next | 一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象: done(boolean) 如果迭代器可以产生序列中的下一个值,则为 false。 如果迭代器已将序列迭代完毕,则为 true。 这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值。 next() 方法必须返回一个对象, 该对象应当有两个属性: done 和 value,如果返回了一个非对象值(比如 false 或 undefined), 则会抛出一个 TypeError 异常(”iterator.next() returned a non-object value”)。 |
Iterator 迭代器是一种接口,为不同的数据结构提供统一的访问机制,这个访问机制主要是遍历,我们知道,在数组、在对象、在类数组、在map、在set里面,都可以用for of或者扩展运算符来得到一个数组或者是遍历当前的数据结构,为什么能够遍历的原因就是因为存在这个Iterator 迭代器这个东西,所以我们可以用for of来提供一个统一的遍历,因此这个底层或者是Itrator它最初是为了for of而设计的。
为了给所有的数据结构有一个统一的遍历接口,统一的访问机制,因此就产生了迭代器。
迭代器的特点:
- 按某种次序排列数据结构
- 为for of提供一个遍历支持
- 为不同的数据结构提供统一的访问机制(目的)
目前所有的内置可迭代对象如下:String、Array、TypedArray、Map 和 Set等,它们的原型对象都实现了 @@iterator 方法。对象(Object)之所以没有默认部署Iterator接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。
例如:由上面的学习,我们知道map的values() 返回的就是一个Iterator对象
展开语法… :
其内部实现也使用了同样的迭代协议
例如:String 是一个内置的可迭代对象
问题:obj is not iterable
怎么做好利用展开值且不报错??
根据mdn迭代器的介绍:
给obj加上一个属性[Symbol.iterator],且返回next()