一、含义
WeakMap 和 Map 一样,都是用于生成键值对的集合
const key=['1',2]; const myWeakMap=new WeakMap().set(key,'2'); console.log(myWeakMap.get(key)) // 2
他也可以接受一个数组来作为参数:
const k1={key:'1'} const k2={key:"2"} const arr=[[k1,'1'],[k2,2]] const myWeakMap=new WeakMap(arr) console.log(myWeakMap.get(k1)) // 1
WeakMap 和 Map 的区别:
(1)WeakMap 只接受对象(null 除外)作为键名
(2)WeakMap 里面的键对象是不会被记入垃圾回收机制的。
注意:WeakMap 弱引用的只是键,而不是键值对,键值对还是正常引用的。
二、WeakMap 的语法
WeakMap 与 Map 在Api 上的区别主要是有两个,一个是没有遍历操作(没有key(),values()和entries()方法),也没有size 属性,因为没有方法列出所有的键名,某个键名是否存在是不可以被知道的,和垃圾回收机制是否运行相关。二是无法清空,即它不支持clear 方法。因此,WeakMap只有四个方法可以使用:get(),set(),has(),delete();
三、WeakMap 的用途
(1)WeakMap 最常见的用途就是把DOM 节点作为键。如下:
let myElement =document.getElementById('logo'); let myWeakmap=new WeakMap(); myWeakmap.set(myElement,{timesClicked:0}); myElement.addEventListener('click',function(){ let logoData=myWeakmap.get(myElement); logoData.timesClicked++ },false)
上面的代码中,myElement 是一个 DOM 节点,每当发生了 click 事件就会更新一下状态,我们将这个状态作为键值放在了WeakMap 里面,对应的键名就是myElement,一旦这个Dom节点删除,这个状态就会消失,不存在内存泄漏的问题。
进一步来讲,可以将事件处理程序存放到 WeakMap 里面来,如下:
const listener=new WeakMap() listener.set(element1,handler1) listener.set(element2,handler2) element1.addEventListener('click',listener.get(element1),false) element2.addEventListener('click',listener.get(element2),false)
(2)WeakMap 的另一用途是缓存计算结果,如下:
const cache=new WeakMap() // 创建一个弱引用 function countKeys(obj){ // 判断弱引用里面是否有obj if(cache.has(obj)){ return [cache.get(obj),'cached'] }else{ const count=Object.keys(obj).length; cache.set(obj,count) return [count,'computed'] } } let obj={name:'kakuqo',age:30}; console.log(countKeys(obj)) // [ 2, 'computed' ] console.log(countKeys(obj)) // [ 2, 'cached' ] obj=null;
(3)WeakMap 还可以用来部署私有属性,如下:
const _counter=new WeakMap(); const _action=new WeakMap(); class Countdown{ // 传递两个参数 constructor(counter,action){ _action.set(this,action); _counter.set(this,counter) } dec(){ let counter=_counter.get(this); if(counter<1) return; counter--; _counter.set(this,counter); if(counter===0){ _action.get(this)() } } } const c=new Countdown(2,()=>console.log('DONE')) c.dec() c.dec() // DONE
由于传递的两个参数都是弱引用,如果删除这个实例,这两个参数也会随之消失,不会造成内存泄漏。