阮一峰ES6教程读书笔记(十)Map数据结构
致自己
自从工作后很久没有看书也没有更文了,因为开发任务重并且逻辑极其复杂,每天回家后什么都不想干了,但是,每天脑海中都有一个声音在提醒我,不能就这样下去,否则终将被时代淘汰。
做技术的核心就在于学习,不断的学习,只有这样才能立于潮头而不会被拍在沙滩上,所以我只能自己鞭策自己向前赶,加油!
Map
1. Map的含义和基本用法
在出现Map
之前,我们一直使用Object
来存储键值对组合,但是这样有一个很大的弊端就是,key-value
组合的key
必须是字符串,如果不是字符串则会被强制转为字符串:
const data = {};
const element = document.getElementsByTagName('div')
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
element.toString() // "[object HTMLCollection]"
通过上面的代码我们可以看出当我们想用一个DOM
节点来当做对象的key
的时候,系统会先调用key
的toString()
方法,那么这样就会使我们在使用Object
数据结构来做key-value
存储时带来了一些风险,因为有时我们可能对key
的toString()
并不太了解。所以我们需要使用一种能够使用任何值作为key
或者value
的数据结构。
cosnt m = new Map()
const key = {name: 'bing'}
m.set(key, 111)
m.has(key) // true
m.get(key) // 111
m.size // 1
上面的代码展示了Map
的一般用法,Map
构造函数接受一个数组生成Map
数据结构。
let arr = [['name', 'bing'], ['age', 23]]
let map = new Map(arr)
// 等价于
arr.forEach([key, value] => {
map.set(key, value)
})
其实,不仅仅是数组,任何成员是一个双元素对并且具有Iterator
接口数据结构都能生成Map
数据结构,比如使用Set
注意:
- 如果使用
set
方法连续对两个相同的键赋值。那么后面的值会覆盖掉前面的值。 - 如果使用
get
读取一个位置的键值,那么返回undefined
。 - 如果
set
的key
是一个对象,那么必须是对同一个对象的引用才能被视作同一个键,即这里看得是内存地址。
2.Map 的实例属性和方法
2.1 size属性
size
返回Map
的成员总数
2.2 Map.prototype.set(key, value)
set
方法设置键名key
对应的键值为value
,然后返回整个Map
结构。如果key
已经有值,则键值会被更新,否则就新生成该键。
2.3 Map.prototpye.get(key)
使用get
从Map
中取键为key
的值
2.4 Map.prototype.has(key)
判断该Map
结构中是否有含有该key
的键值对,该方法返回一个布尔值来表示是否存在
2.5 Map.prototype.delete(key)
delete
方法用来删除某个键,如果成功就返回true
失败返回false
const map = new Map([['name', 'bing'], ['age', 23]])
map.delete('name') // true
map.delete('name') // false
可以看到,如果这个键不存在与该Map
结构中,如果使用删除操作也是会被判定失败的。
2.6 Map.prototype.clear()
清除Map
中所有的值,该方法没有返回值。
3. Map的遍历操作
Map
提供3个遍历器生辰函数和一个遍历方法:
-
Map.prototype.keys()
:返回键名的遍历器。 -
Map.prototype.values()
:返回键值的遍历器。 -
Map.prototype.entries()
:返回所有成员的遍历器。 -
Map.prototype.forEach()
:遍历 Map 的所有成员。
值得注意的是,返回遍历器的元素的顺序就是Map
插入元素的顺序
let map = new Map()
map.set('name', 'bing')
map.set('age', 23)
for (let [key, value] of map.entries()) {
console.log(key, value)
}
// name bing
// age 23
for (let [key, value] of map) {
console.log(key, value)
}
// name bing
// age 23
通过上面的代码可以看出Map
的Iterator
接口默认就是entries
方法
4. 关于Map的编程技巧
4.1
Map
本身不具备数组的遍历方法,除了forEach
,这时候我们可以通过扩展运算符将Map
快速转成Array
,然后调用数组的遍历方法,操作完之后再使用构造函数Map()
将其转为Map
4.2
Map
的forEach
方法可以接受第二个参数来绑定this
,这样我们就可以在forEach
的函数作用域内来对this
绑定的对象进行操作,例如:
let map = new Map()
map.set('name', 'bing')
map.set('age', 23)
let person = {}
map.forEach(function(key, value){
this[key] = value
}, person)
person // {23: "age", bing: "name"}
请注意key
和value
的位置,这里很容易形成误导。
值得注意的是,这里可能会有人犯一个非常小的错误,就是我们可能在平时开发中经常使用箭头函数,在这里我们如果将传入forrrEach
的方法使用箭头函数定义了,那么函数将不能正常执行,因为箭头函数会绑定this
为其定义时的环境。一般情况下,这里的this都会是Window
。
let map = new Map()
map.set('name', 'bing')
map.set('age', 23)
let person = {}
map.forEach((value, key) => {
this[key] = value
}, person)
person // {}
window.name // "bing"
window.age // 23
4.3 Array
转Map
可以通过构造函数很方便地将数组转为Map
。
let arr = [['name', 'bing']]
const map = new Map(arr)
map // {"name" => "bing"}
4.4 Map
转为Array
使用扩展运算符能够很方便的将Map
转为Array
let map = new Map().set('name', 'bing')
let arr = [...map]
arr // ["name", "bing"]
4.5 Map
和Object
的相互转换
这两种数据结构之间的相互转换主要依靠遍历,然后调用赋值语句或者Map
的set
方法。
4.6 Map
转为 JSON
分两种情况讨论,如果Map
的键名都是字符串,那么我们可以先把Map
转为对象,然后再转为JSON
,其次,如果Map
的键有的不是字符串,那么我们可以考虑将其转为数组,然后再将其转为JSON
,这样的话,我们就可以保留特殊键。
参考链接
作者:阮一峰
连接:http://es6.ruanyifeng.com/#docs/set-map