上期内容,我们一起从ES6
规范的起源介绍开始,重点聊了下在实际场景中被大家忽略Set的使用,今天我们就来一起看看同样被大家可能忽视的Map
。还是跟上期一样,我们不长篇大论讲Map
的基础API
,因为这个大家都会去查文档,我们聊聊几点需要重点掌握的东西。
肯定有很多同学会讲,哪里需要Map
呀,本少爷Object
行天下。有没有想起那个jQuery的梗,来点画面感。
什么是Map
Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。 --MDN
使用场景
大家经常会使用Object
进行Key-Value
也就是我们常说的键值对的处理,本质上就是一种Hash
结构,但是在JavaScript中的是只能使用字符串当作key
的,这个在使用上就会有一定的限制。
大家可以看到,尽管obj
在初始化的时候,1是number
类型,但是我们在内省的时候,typeof
的结果还是字符串。这样可能在更严格的场景下,给我们带来类型识别上的障碍。当然事实上,Object
的key
还可以是Symbol
,这里额外提醒下大家。
阮一峰大佬的ES6一书中也提到了一个例子
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
上面代码原意是将一个 DOM 节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement]。--《ECMAScript 6 入门》
我们使用Map
再来尝试下
这个时候,key
的类型就是我们想要的情况了。
Tip
MDN
的文档上也特意提到一个事情,其实在上期Set
的文章笔者提到了,就是有关NaN。大家都知道NaN 和任何值甚至和自己都不相等(NaN !== NaN 返回true),但是呢在Set
和Map
场景下,是有所不同的。
let myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN); // "not a number"
let otherNaN = Number("foo");
myMap.get(otherNaN); // "not a number"
简而言之在NaN
作为Key
的时候,还是会当成一样的来处理,所以大家要学习不能学的过于死板。(之前讲过xxx,所以这里也是xxx,这种方式是不好的)
Map跟Object的区别
源自MDN
Map | Object | |
---|---|---|
意外的键 | Map 默认情况不包含任何键。只包含显式插入的键。 | 一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。备注:虽然 ES5 开始可以用 Object.create(null) 来创建一个没有原型的对象,但是这种用法不太常见。 |
键的类型 | 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。 | 一个Object 的键必须是一个 String或是Symbol。 |
键的顺序 | Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 | 一个 Object 的键是无序的备注:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。 |
Size | Map 的键值对个数可以轻易地通过size属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable的,所以可以直接被迭代。 | 迭代一个Object需要以某种方式获取它的键然后才能迭代。 |
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
这里还有一个小知识,就是Map
实例对象是支持链式操作的,这个词相信使用过jQuery
的同学很熟悉。
其他常用实例属性和方法
- Size 属性,返回 Map 结构的成员总数
- has 方法,返回一个布尔值,表示某个键是否在当前 Map 对象之中
- delete 方法,删除某个键,返回
true
。如果删除失败,返回false
- clear 方法,清除所有成员,没有返回值
Map的常见遍历方式
- for..of
let miaoMap = new Map();
miaoMap.set('name', '喵爸');
miaoMap.set('age', 32);
for (let [key, value] of miaoMap) {
console.log(key + " = " + value);
}
// 将会显示两个log。一个是"name = 喵爸"另一个是"age = 32"
for (let key of miaoMap.keys()) {
console.log(key);
}
for (let value of miaoMap.values()) {
console.log(value);
}
for (let [key, value] of miaoMap.entries()) {
console.log(key + " = " + value);
}
- forEach
miaoMap.forEach(function(value, key) {
console.log(key + " = " + value);
})
下期我们再聊下Map
对应还有个兄弟WeakMap
写在最后
感谢大家的阅读,如果大家喜欢可以点个关注,也可以关注下公粽号:喵爸的小作坊