Map与WeakMap详解
前言
今天有个要将对象作为键的需求,传统的Object不能满足,因此特意巩固一下Map的用法,在此记录一下。
Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
引自:https://es6.ruanyifeng.com/#docs/set-map#Map
用法
- 对象作为key
const m=new Map();
const o={p:'hello world'};
m.set(o,'content');
console.log(m.get(o))//content
上面用法就是将object对象作为m的key,同时使用get方法得到这个key的值。
- 数组作为key
const m=new Map([['name','张三'],['age',15]]);
console.log(m.has('name'))//true
console.log(m.has('age'))//true
console.log(m.get('name'))//张三
console.log(m.get('age'))//15
console.log(m.get('sex'))//undefined
上面代码在新建 Map 实例时,就指定了两个键name、age,get方法读取key对应的键值,如果找不到key,返回undefined。
- 遍历方法
Map.prototype.keys():返回键名的遍历器。
Map.prototype.values():返回键值的遍历器。
Map.prototype.entries():返回所有成员的遍历器。
Map.prototype.forEach():遍历 Map 的所有成员。
const m=new Map([['name','张三'],['age',15],['sex']]);
for(let key of m.keys()){
console.log(key)
}
for(let value of m.values()){
console.log(value)
}
for(let item of m.entries()){
console.log(item[0],item[1])
}
m.forEach((value,key)=>{
console.log(value,key)
})
- 与其他数据结构的互相转换
//Map转数组
const m=new Map([['name','张三'],['age',15],['sex']]);
console.log([...m])
//Map转为对象
const o=new Map();
o.set('name','张三');
o.set('age',13);
function mapToObj(str){
let obj=Object.create(null);
for(let [k,v] of str){
obj[k]=v;
}
return obj
}
console.log(mapToObj(o));
//对象转为 Map
let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));
WeakMap
WeakMap结构与Map结构类似,也是用于生成键值对的集合
首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
其次,WeakMap的键名所指向的对象,不计入垃圾回收机制
它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用
WeakMap 与 Map 在 API 上的区别主要是两个,一是没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性。因为没有办法列出所有键名,某个键名是否存在完全不可预测,跟垃圾回收机制是否运行相关。这一刻可以取到键名,下一刻垃圾回收机制突然运行了,这个键名就没了,为了防止出现不确定性,就统一规定不能取到键名。二是无法清空,即不支持clear方法。因此,WeakMap只有四个方法可用:get()、set()、has()、delete()。
WeakMap 的用途
WeakMap 应用的典型场合就是 DOM 节点作为键名
let myWeakmap = new WeakMap();
myWeakmap.set(
document.getElementById('logo'),
{timesClicked: 0})
;
document.getElementById('logo').addEventListener('click', function() {
let logoData = myWeakmap.get(document.getElementById('logo'));
logoData.timesClicked++;
}, false);
上面代码中,document.getElementById('logo')是一个 DOM 节点,每当发生click事件,就更新一下状态。我们将这个状态作为键值放在 WeakMap 里,对应的键名就是这个节点对象。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。