我们知道,JavaScript 垃圾回收机制中,JavaScript 引擎在值可访问时将其存储在内存中。但是当引用消失时,该值就会被回收。
// 该对象能被访问,coolFish 是它的引用
let people = { name: "coolFish" };
// 覆盖引用
people = null;
// 该对象将会被从内存中清除
但是如果把一个对象放进数组中,那么只要数组在,对象就存在,即使没有对该对象的引用。
let people = { name: "coolFish" };
let array = [ people ];
people = null; // 覆盖引用
// 前面由 people 所引用的那个对象被存储在了 array 中
// 所以它不会被垃圾回收机制回收
如果我们使用对象作为常规 Map
的键,那么当 Map
存在时,该对象也将存在。它会占用内存,并且应该不会被(垃圾回收机制)回收。
WeakMap
WeakMap 和 Map 的第一个不同点就是 WeakMap 的键必须是对象,不能是原始值。
let people = { name: "coolFish" };
let weakMap = new WeakMap();
weakMap.set(people, "ok"); // 正常工作(以对象作为键)
weakMap.set("test", "Whoops"); // Error,因为 "test" 不是一个对象
people = null; // 覆盖引用 // people 被从内存中删除了!
我们可以发现,如果people
只是作为 WeakMap 的键而存在,他们会被从 map 中自动删除。
WeakMap
不支持迭代以及 keys()
,values()
和 entries()
方法。所以没有办法获取 WeakMap
的所有键或值。
我们可以用下面几个方法,获取一些我们想要的信息
- weakMap.get(key) ,拿键取值。
- weakMap.set(key,value) ,设置weakMap
- weakMap.delete(key) ,根据键删除值
- weakMap.has(key) ,是否包含该键
这种限制的原因是,当 weakMap 中的对象失去他的所有引用,就会开始自动垃圾回收,垃圾回收时,可能会立即回收,也可能当前有很多回收任务,所以会延迟回收,这样我们就不知道**何时会被回收**
,因此不支持访问 WeakMap的所有键值的方法。
WeakMap 使用场景
WeakMap
的主要应用场景是 额外数据的存储。
例如我们在处理一个属于另外一个代码的一个对象,并且想存储一些相关的数据,那么这些数据就应该和这个对象共存亡,这时候 WeakMap 就是我们需要的,我们把这些数据放到 WeakMap 中,并且使用该对象作为这些数据的键 ,那么当该对象被垃圾回收了,数据也会被回收,同理,当数据不存在的时候,对象也会被回收。
我们来看一个缓存案例
//首先我们创建一个缓存函数
let cache = new Map()
//计算并且记住结果
function process(obj) {
if (!cache.has(obj)) {
let result = obj;
cache.set(obj, result);
}
return cache.get(obj);
}
//我们在其他文件使用他时
let obj = {/* 假设我们有个对象 */};
let result1 = process(obj); // 计算完成
// ……稍后,来自代码的另外一个地方……
let result2 = process(obj); // 取自缓存的被记忆的结果
// ……稍后,我们不再需要这个对象时:
obj = null;
alert(cache.size); // 1(啊!该对象依然在 cache 中,并占据着内存!)
小结:我们可以看到,我们应用缓存函数时,将我们传入的对象,作为 map 的键,所以当我们初始化对象的时候,该对象会依旧在 cache 中,因为他被定义在 cache 中的键。
要解决该问题,我们可以使用 WeakMap 这样当键这个对象不可访问时,即便他作为键,他也会被一同被内存中删除。
WeakSet
- 与
Set
类似,但是我们只能向WeakSet
添加对象(而不能是原始值)。 - 对象只有在其它某个(些)地方能被访问的时候,才能留在 set 中。
- 跟
Set
一样,WeakSet
支持add
,has
和delete
方法,但不支持size
和keys()
,并且不可迭代。
我们可以把对象添加到 WeakSet中,以便去重,并且当对象不可读取时,他会进行垃圾回收。
let visitedSet = new WeakSet();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
visitedSet.add(john); // John 访问了我们
visitedSet.add(pete); // 然后是 Pete
visitedSet.add(john); // John 再次访问
// visitedSet 现在有两个用户了
// 检查 John 是否来访过?
alert(visitedSet.has(john)); // true
// 检查 Mary 是否来访过?
alert(visitedSet.has(mary)); // false
john = null;
// visitedSet 里将只有pete
总结
WeakMap
是类似于 Map
的集合,它仅允许对象作为键,并且一旦通过其他方式无法访问它们,便会将它们与其关联值一同删除。
WeakSet
是类似于 Set
的集合,它仅存储对象,并且一旦通过其他方式无法访问它们,便会将其删除。
它们都不支持引用所有键或其计数的方法和属性。仅允许单个操作。
WeakMap
和 WeakSet
被用作“主要”对象存储之外的“辅助”数据结构。一旦将对象从主存储器中删除,如果该对象仅被用作 WeakMap
或 WeakSet
的键,那么它将被自动清除。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!