1. WeakMap 是什么?
WeakMap 与 Map 类似,也是生成 键值对的组合,但是有区别:
只能接受对象作为键名(不包括null);
键名所指向的对象是弱引用,不计入垃圾回收机制;
弱引用是键名,而不是键值,键值依然是正常引用的;
原因:没有办法列出所有键名,某个键名是否存在完成不可预测,这和垃圾回收机制是否允许相关:就算这一刻可以取到键名,下一刻垃圾回收机制突然运行的话这个键名就可能消失,为了防止这种不确定性,所以统一规定不能取到键名)
2. WeakMap防止内存泄露?
dom元素上添加数据时可用 WeakMap,用 WeakMap 好处是当该 DOM 元素被清除,对应的 WeakMap记录就会自动被移除。
例1:
const wm = new WeakMap();
const ele = document.getElementById('example');
wm.set(el, 'some information');
wm.get(el) //"some information"
注册监听事件的listener对象很适合用WeakMap来实现。
例2:
// 代码1
ele.addEventListener('click', handler, false);
// 代码2
const listener = new WeakMap();
listener.set(ele, handler);
ele.addEventListener('click', listener.get(ele), false);
代码2比起代码1的好处是:由于监听函数是放在 WeakMap 里面,
则一旦dom对象ele消失,与它绑定的监听函数handler也会自动消失
3. WeakMap 可用来部署类中的私有属性
(ts中已经实现的private私有属性原理就是利用weakmap)
私有属性应该是不能被外界访问到,不能被多个实例共享,js中约定俗成的使用下划线来标记私有属性和方法,一定程度来说是不靠谱的。
下面使用三种方法来实现:闭包(版本1)=》Symbol(版本2)=》WeakMap(版本3)
//简单使用闭包(版本1)
const testFn = (function () {
let data;
class Test {
constructor(val) {
data = val
}
getData() {
return data;
}
}
return Test;
})();
let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData());//4
console.log(test2.getData());//4
可以看到最后都输出4,多实例共享私有属性了,所以版本1不符合。
//使用Symbol(版本2)
const testFn = (function () {
let data = Symbol('data')
class Test {
constructor(val) {
this[data] = val
}
getData() {
return this[data]
}
}
return Test;
})();
let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData());//3
console.log(test2.getData());//4
console.log(test1[Object.getOwnPropertySymbols(test1)[0]]); // 3
console.log(test2[Object.getOwnPropertySymbols(test2)[0]]); // 4
版本2使用symbol来实现,虽然正确输出了3,4,但是我们发现可以在外界不通过getData方法,而是直接拿到私有属性,所以版本2也不符合。
//使用WeakMap(版本3)
const testFn = (function () {
let data = new WeakMap()
class Test {
constructor(val) {
data.set(this, val)
}
getData() {
return data.get(this)
}
}
return Test;
})();
let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData());//3
console.log(test2.getData());//4
如上,完美解决~~
完结撒花,有疑问留言探讨哈~~~