含义和基本用法
JavaScript的对象本质上是键值的集合(Hash结构),只能用字符串作为键。给使用带来了很大的限制。
const data = {}
const element = document.getElementById("mydiv")
data[element] = 'metadata'
data['[object HTMLDivElement]'] //"metadata"
复制代码
为了解决这个问题,ES6提供可Map结构。类似于对象,也是键值的结合,但是键的限制范围不再只是字符串,各种类型包括对象都可以当作键。Map提供了“值---值”对应,是一种更加完善的Hash结构,如果需要键值对的数据结构,Map比Object更加适合。
const m = new Map()
const o = {p:"hello"}
m.set(o,'content')
m.get(o) // "content"
m.has(o) //true
m.delete(o) // true
m.has(o) // false
复制代码
Map也可以接受一个数组作为参数,该数组成员是一个个表示键值对的数组
const map = new Map([
['name','zhangsan'],
['title','auther']
])
map.size //2
map.has('name') //true
map.get('name') //"zhangsan"
复制代码
Map 构造函数接受数组作为参数,实际上是执行了下边的算法:
const items = [
['name','zhangsan'],
['title','auther']
]
const map = new Map()
items.forEach(
([value,key]) => map.set(key,value)
);
复制代码
不仅仅是数组,任何具有 iterator 接口,且每个成员都是一个双元素数组的数据结构,都可以当作Map构造函数的参数,Set 和 Map 都可以用来生成新的Map。
注意:只有同一个键的引用,Map结构才会将其视为同一个键。
const map = new Map();
map.set(['a'],555);
map.get(['a']); // undefined
复制代码
上面set和get表面上针对了同一个键,但是实际上是两个值,内存地址是不一样的,因此get 无法读取该键。
如果Map的键是一个简单类型(数字,字符串,布尔值),只要两个值严格相等,Map就会将其视为一个键,包括 0 -0,另外,虽然NaN不严格等于自身,但是Map将其视为一个键。
实例属性和操作方法
size 属性
返回map结构的成员总数
set(key,value)
set方法设置key所对应的键值,然后返回整个Map结构。如果key已经存在,则键值会被更新,否则新生成该键。
get(key)
get 获取 key 对应的键值,如果找不到 key,返回undefined。
has(key)
has返回一个布尔值,表示某个键是否在Map结构中
delete(key)
delete删除某个键,返回true,删除失败返回false
clear()
清除所有成员,没有返回值。
遍历方法
一共3个遍历器生成函数和1个遍历方法
- keys() 返回键名
- values() 返回键值
- entries() 返回所有成员
- forEach() 遍历map所有成员
注意:Map的遍历顺序就是插入顺序。
const map = new Map([
['f','no'],
['t','yes']
])
for(let key of map.keys()) {
}
for(let key of map.values()) {
}
for(let key of map.entries()) {
}
for(let [key,value] of map.entries()) {
}
// 等同于使用 map.entries()
for(let [key,value] of map) {
}
复制代码
Map 结构转为数组结构比较快速的方法是 扩展运算符(...)
const map = new Map([
['f','no'],
['t','yes']
])
[...map.keys()] // ['f','t']
[...map.values()] //['no','yes']
[...map.entries()] // [['f','no'],['t','yes']]
[...map] // [['f','no'],['t','yes']]
复制代码
结合数组的map方法,filter方法,实现Map结构的遍历和过滤
const map0 = new Map().set(1,'a').set(2,'b').set(3,'c')
const map1 = new Map(
[...map0].filter(([k,v]) => k<3)
)
// Map {1 => 'a', 2 => 'b'}
const map1 = new Map(
[...map0].map(([k,v]) => [k*2,'_' + v])
)
// Map {2 => '_a', 4 => '_b', 6 => '_c'}
复制代码
Map 还有一个forEach方法,于数组的forEach相似
map.forEach(function(value,key,map) {
console.log("Key: %s, Value: %s",key,value)
})
复制代码
forEach 可以接受第二个参数,用来绑定this
const reporter = {
report: function(key,value) {
console.log("Key: %s, Value: %s",key,value)
}
}
map.forEach(function(value,key,map) {
this.report(key,value)
}.reporter)
复制代码
与其他结构转换
Map转为数组
(...map)
数组转Map
new Map([
[true,7],
[{foo:3},['abc']]
])
复制代码
Map转对象
如果map所有键都是字符串,可以转化为对象
function strMapToObj(strMap){
let obj = Object.create(null)
for(let [k,v] of strMap){
obj[k] = v
}
return obj
}
const myMap = new Map().set('yes',true).set('no',false)
复制代码
对象转Map
function objToStrMap(obj){
let strMap = new Map()
for(let k of Object.keys(obj)){
strMap.set(k, obj[k])
}
return strMap
}
objToStrMap({yes:true,no:false})
复制代码
Map转JSON
Map转JSON分两种情况,一种是 键名都是字符串,这时可以转化为对象JSON
function strMapToJson(strMap){
return JSON.stringify(strMapToObj(strMap))
}
let map = new Map().set(['yes',true]).set(['no',false])
strMapToJson(map)
//'{"yes":true,"no":false}'
复制代码
另一种,Map键名不是字符串,转化为数组JSON
function mapToArrayJson(map) {
return JSON.stringify([...map])
}
let map = new Map().set(['yes',true]).set([{foo:3},[a,c,b]])
mapToArrayJson(map)
// '[['yes',true],[{foo:3},[a,c,b]]]'
复制代码
JSON转Map
function jsonToStrMap(josnStr) {
return objToStrMap(JSON.parse(jsonStr))
}
jsonToStrMap('{"yes":true,"no":false}')
// Map {'yes' => true, 'no' => false}
复制代码