ES6为何加入WeakSet、WeakMap

简介: ES6为何加入WeakSet、WeakMap

垃圾回收(Garbage Collection)机制中的可达性(Reachability)

不同于C或C++,Javascript作为一种高级编程语言,在创建对象时会自动分配内存,而当对象不再被使用时会自动清除内存(C或C++由开发者主动去调取相应的 API 来完成空间管理,而Js中没有提供相应API)。对象不再被使用而被释放内存的过程被成为垃圾回收

谈到垃圾回收机制,就必须要理解垃圾回收机制中的可达性(Reachability)概念

可达性:可以通过引用、作用域链等方式访问到的对象就是可达对象

举个例子:

let obj = { name: "xm" }; // 创建了一个对象,这个对象的引用次数为1
let ali = obj; // 对象的引用次数变为2
obj = null; // 对象的引用次数变为1,依然是可达对象
复制代码

再举个例子:

function objGroup(obj1, obj2) {
  obj1.next = obj2;
  obj2.prev = obj1;
  return {
    o1: obj1,
    o2: obj2,
  };
}
let obj = objGroup({ name: "obj1 name" }, { name: "obj2 name" });
delete obj.o1    // 取消了 obj 中 o1 的引用
delete obj.o2.prev    // 取消了 obj2 中对于 o1 的引用,此时就无法找到 obj1 这个对象空间,obj1 就会被认为是垃圾,被回收
复制代码

强引用

继续用上个例子:

let obj = { name: "xm" }; // 创建了一个对象,这个对象的引用次数为1
let ali = obj; // 对象的引用次数变为2
obj = null; // 对象的引用次数变为1,依然是可达对象
console.log(ali)   // 依然可以打印出 { name: 'xm' }
复制代码

发现当obj被置为null了,但打印ali的时候还是能打印出对象内容。这是因为ali与对象之间存在强引用,强引用能够阻止对象被垃圾回收。

弱引用

通常情况下,Javascript中对对象的引用是强引用,要在Javascript中实现弱引用,怎么办呢?别担心,ES6中已经引入了WeakSet 与 WeakMap,弱引用不再是问题。

let human = new WeakMap();
let man = { name: "Joe Doe" };
human.set(man, "done")
console.log(human.get(man))   // 输出done
man = null
console.log(human.get(man))  //  输出undefined
复制代码

上述代码,当man参数被设置为null时,内存中对原始对象的唯一引用(weakMap对其的引用)是弱引用,弱引用不会阻止垃圾回收

WeakSet与WeakMap 的应用领域

缓存(Caching)

举个例子:我们创建一个cachedResult.js的文件,内容如下:

let cachedResult = new Map();
function keep(obj) {
  if (!cachedResult.has(obj)) {
    let result = obj;
    cachedResult.set(obj, result);
  }
  return cachedResult.get(obj);
}
console.log(cachedResult.size);  //  打印出 0, Map(0) {}
let obj = { name: "Frank" };
let resultSaved = keep(obj)
obj = null;
console.log(cachedResult.size);  // 打印出 1, Map(1) { { name: 'Frank' } => { name: 'Frank' } }
复制代码

假设使用Map,在我们不需要obj对象时,需要去手动清理cachedResult对象。而当我们换成WeakMap,我们不需要去主动清理,也就是说,一旦对象被垃圾收集,缓存的结果将自动从内存中删除:

let cachedResult = new WeakMap();
// A function that stores a result.
function keep(obj) {
  if (!cachedResult.has(obj)) {
    let result = obj;
    cachedResult.set(obj, result);
  }
  return cachedResult.get(obj);
}
let obj = { name: "Frank" };
let resultSaved = keep(obj)
console.log(cachedResult.get(obj));   // 打印出 { name: 'Frank' }
obj = null;
console.log(cachedResult.get(obj));  // 打印出 undefined
复制代码

额外的数据存储

假设我们正在构建一个电子商务(e-commerce)平台,其中有一个统计访客的程序,那么在访客离开时,统计的数量visitorCount需要相应减小。这个功能如果使用Map的话,就很容易出现bug(在客户离开时需要对visitorCount进行内存释放,否则会在内存中无限增长,占用内存),但如果是使用WeakMap,就不需要主动对visitorCount进行释放(一旦人(对象)无法访问,就会被自动被垃圾回收)。

let visitorCount = new WeakMap();
function countCustomer(customer){
   let count = visitorCount.get(customer) || 0;
    visitorCount.set(customer, count + 1);
}
复制代码
let person = {name: "Frank"};
countCustomer(person)  // 访客访问时
person = null;  // 访客离开时
复制代码

总结

WeakSet、WeakMap的出现,主要是为了避免容易忽视的内存泄漏。

相关链接:

Understanding Weak Reference In JavaScript



相关文章
|
4月前
|
存储 JavaScript 前端开发
【JavaScript】Set、Map、WeakSet、WeakMap
Set、Map、WeakSet和WeakMap是ES6引入的新的数据结构,它们在处理数据时具有不同的特性和用途。本文将详细介绍它们的用法、特性、区别、优缺点以及使用场景和注意事项,并给出相应的代码示例
48 0
|
2月前
|
存储 缓存 JavaScript
javascript中的WeakMap和WeakSet
javascript中的WeakMap和WeakSet
|
3月前
|
存储 JavaScript 前端开发
ES6中的WeakMap和WeakSet:特性和用途
在JavaScript的ES6版本中,引入了两种新的数据结构——WeakMap和WeakSet。与Map和Set相比,这两种数据结构有一些特殊的特点和用途,因此在某些场合下,它们是更好的选择。本文将深入探讨WeakMap和WeakSet的特性和用途。
|
4月前
|
存储 缓存 前端开发
WeakMap 和 WeakSet:解决内存泄漏&避免循环引用(上)
WeakMap 和 WeakSet:解决内存泄漏&避免循环引用(上)
|
4月前
|
存储 缓存 Java
WeakMap 和 WeakSet:解决内存泄漏&避免循环引用(下)
WeakMap 和 WeakSet:解决内存泄漏&避免循环引用(下)
WeakMap 和 WeakSet:解决内存泄漏&避免循环引用(下)
|
5月前
|
存储 Java
ES6中的WeakMap和WeakSet:特性和用途2
ES6中的WeakMap和WeakSet:特性和用途2
19 1
|
6月前
ES6常见的数组方法
ES6常见的数组方法
27 1
|
9月前
|
Java API
【Map 和 WeakMap 的区别】
【Map 和 WeakMap 的区别】
84 0
|
11月前
|
存储
一文搞清楚ES6新增数据结构 Symbol Map WeakMap Set WeakSet(一)
一文搞清楚ES6新增数据结构 Symbol Map WeakMap Set WeakSet
84 0
|
11月前
|
存储 Java 对象存储
一文搞清楚ES6新增数据结构 Symbol Map WeakMap Set WeakSet(二)
一文搞清楚ES6新增数据结构 Symbol Map WeakMap Set WeakSet
87 0