weakMap

weakMap的特性及应用场景总结:

特性

WeakMap 只接受对象作为键名

1
2
3
4
5
const map = new WeakMap();
map.set(1, 2);
// TypeError: Invalid value used as weak map key
map.set(null, 2);
// TypeError: Invalid value used as weak map key

WeakMap 的键名所引用的对象是弱引用

​ WeakMaps 保持了对键名所引用的对象的弱引用。在计算机程序中弱引用和强应用是相对的,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。

在JavaScript中,一般我们创建的对象,都是强引用;

1
var obj = new Object();

只有当我们手动设置为null时,才会回收obj

如果创建一个弱引用对象:

1
2
// 假设可以这样创建一个
var obj = new WeakObject();

那么垃圾回收机制执行时,obj所引用的对象会被回收。

正常情况:

1
2
3
4
const key = new Array(5 * 1024 * 1024);
const arr = [
[key, 1]
];

使用这种方式,我们其实建立了 arr 对 key 所引用的对象(我们假设这个真正的对象叫 Obj)的强引用。所以当你设置 key = null 时,只是去掉了 key 对 Obj 的强引用,并没有去除 arr 对 Obj 的强引用,所以 Obj 还是不会被回收掉。Map 类型也是类似:

1
2
3
4
5
6
7
let map = new Map();
let key = new Array(5 * 1024 * 1024);

// 建立了 map 对 key 所引用对象的强引用
map.set(key, 1);
// key = null 不会导致 key 的原引用对象被回收
key = null;

如果你想要让 Obj 被回收掉,你需要先 delete(key) 然后再 key = null:

1
2
3
4
5
let map = new Map();
let key = new Array(5 * 1024 * 1024);
map.set(key, 1);
map.delete(key);
key = null;

WeakMaps 保持了对键名所引用的对象的弱引用:

1
2
3
4
const wm = new WeakMap();
let key = new Array(5 * 1024 * 1024);
wm.set(key, 1);
key = null;

当设置 wm.set(key, 1) 时,其实建立了 wm 对 key 所引用的对象的弱引用,但因为 let key = new Array(5 1024 1024) 建立了 key 对所引用对象的强引用,被引用的对象并不会被回收,但是当我们设置 key = null 的时候,就只有 wm 对所引用对象的弱引用,下次垃圾回收机制执行的时候,该引用对象就会被回收掉。

因此,WeakMap 可以帮我们省掉手动删除对象关联数据的步骤。弱引用的特性,就是 WeakMaps 保持了对键名所引用的对象的弱引用,即垃圾回收机制不将该引用考虑在内。只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。

也正是因为这样的特性,WeakMap 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakMap 不可遍历。

所以 WeakMap 不像 Map,一是没有遍历操作(即没有keys()、values()和entries()方法),也没有 size 属性,也不支持 clear 方法,所以 WeakMap只有四个方法可用:get()、set()、has()、delete()。

应用

DOM 对象上保存相关数据

​ 传统使用 jQuery ,我们通过 $.data() 方法在 DOM 对象上储存相关信息(就比如在删除按钮元素上储存帖子的 ID 信息),jQuery 内部会使用一个对象管理 DOM 和对应的数据,当你将 DOM 元素删除,DOM 对象置为空的时候,相关联的数据并不会被删除,你必须手动执行 $.removeData() 方法才能删除掉相关联的数据,WeakMap 就可以简化这一操作:

1
2
3
4
5
6
7
8
let wm = new WeakMap(), element = document.querySelector(".element");
wm.set(element, "data");

let value = wm.get(elemet);
console.log(value); // data

element.parentNode.removeChild(element);
element = null;

数据缓存

​ 在不修改原有对象的情况下储存某些属性或者根据对象储存一些计算的值等,而且又不用管理这些数据的死活时非常适合考虑使用 WeakMap。

1
2
3
4
5
6
7
8
9
10
11
12
const cache = new WeakMap();
function countOwnKeys(obj) {
if (cache.has(obj)) {
console.log('Cached');
return cache.get(obj);
} else {
console.log('Computed');
const count = Object.keys(obj).length;
cache.set(obj, count);
return count;
}
}

私有属性

WeakMap 也可以被用于实现私有变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const privateData = new WeakMap();

class Person {
constructor(name, age) {
privateData.set(this, { name: name, age: age });
}

getName() {
return privateData.get(this).name;
}

getAge() {
return privateData.get(this).age;
}
}

export default Person;

原文地址(冴羽)

https://segmentfault.com/a/1190000015774465

-------------本文结束感谢您的阅读-------------