您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

ES6+ WeakMap

前面我们已经学了 Set 和对应的 WeakSet,Map 对应也有 WeakMap,在学习 WeakSet 时我们已经接触到弱引的相关知识,本节我们将结合 WeakMap 深入的理解的相关问题。

由前面学到的 Set 和 WeakSet 具有很多相似的地方,比如它们存放的都是独一无二的元素。所以,对 Map 和 WeakMap 也可以进行类比,WeakMap 中也存放的是键值对。不同的是 WeakMap 的 key 只能是对象,值可以是任意类型的,和 WeakSet 一样 WeakMap 对 key 的引用是。

WeakMap 像 Map 一样可以接受二维数组进行初始化。

var wm = new WeakMap([
  [{name: 'imooc'}, 'imooc'],
  [{name: 'lesson'}, 'ES6 Wiki']
])
console.log(wm)

上面的打印结果如下:

从打印的结果可以大概了解 WeakMap 的存储方式,WeakMap 的实例本来就是对象。

WeakMap 只提供了四个用于操作数据。

看如下实例:

var wm1 = new WeakMap();
var wm2 = new WeakMap();
var wm3 = new WeakMap();

var o1 = {name: 'imooc'};
var o2 = function(){};
var o3 = window;

// 使用 set 元素,value 可以是任意值,对象、甚至另外WeakMap对象
wm1.set(o1, 'ES6 Wiki');
wm1.set(o2, );
wm2.set(o1, o2);
wm2.set(o3, null);
wm2.set(wm1, wm2);

wm1.get(o2); // 10
wm2.get(o2); // undefined,wm2 中没有 o2 这个键
wm2.get(o3); // null

wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (即使值是null)

wm3.set(o1, 'lesson is ES6 Wiki!');
wm3.get(o1); // lesson is ES6 Wiki!

wm1.has(o1);   // true
wm1.delete(o1);
wm1.has(o1);   // false

上面的实例基本涵盖了 WeakMap 四种的基本使用情况,上面也提到了 WeakMap 的 key 只能是对象类型的,如果 WeakMap 的 key 是基本类型数据时就会报错。

var wm = new WeakMap();
wm.set('lesson', 'ES6 Wiki');
// Uncaught TypeError: Invalidvalue used as weak map key

上面中在设置 wm 值时,报错了。从报错类型知道是类型,映射的键是无效的。

上节我们学习了 Map 的使用,在 JavaScript 中对对象的引用都是强保留的,这意味着只要持有该对象的引用,回收机制就不会回收该对象。

var obj = {a: , b: };

上面是字面量对象,只要我们访问 obj 对象,或者任何地方有引用该对象,这个对象就不会被回收。而在 ES6 之前 JavaScript 中没有概念,的本质上就是不会影响回收机制。其实,WeakMap 并不是真正意义上的,只要键仍然存在,它就强引用其上的。WeakMap 仅在键被回收之后,才它的,所以也不用太纠结其中的弱。

在官方上对为什么使用 WeakMap 做了描述,Map 在存储值是有顺序的,这种顺序是通过二维数组的形式来完成的。我们知道 Map 在初始化时接受数组,数组中的每一项也是数组,这个数组中包含两个值,存放的是键,存放的是值。新的值会到数组的末尾,从而使得键值具有索引的含义。在取值时就需要进行遍历,通过索引取出对应的值。

但是这样存在两个很大的缺陷:

相比之下,原生的 WeakMap 持有的是 “”,这意味着它不会影响回收。WeakMap 中的 key 只有在键值存在的情况才会引用,而且只是读取操作,并不会对引用的值产生影响。也正因为这样的关系,导致 WeakMap 中的 key 是不可枚举的,假设 key 是可枚举的,就会对该值产生引用关系,影响回收。

如果只是单纯地向对象上值用于检查某些逻辑判断,又不想影响回收机制,这个时候就可以使用 WeakMap。这里说一点,在一些框架中已经使用了像 WeakMap 和 WeakSet 这样的数据结构,其中 Vue3 就引入了这样的新数据进行一些必要的逻辑判断,有兴趣的可以去扒扒 Vue3 的源码研究研究。

本节主要介绍了 WeakMap 的使用和应用场景,这里要说明的一点是:WeakMap 不算真正意义上的方式,只要键仍然存在,它就强引用其上的。最新的 ES 方案提出了 WeakRef 的 API 作为真正的方式,现在还处于不稳定期间,也还存在一些问题,如果有兴趣的可以研究一下。最后,在 WeakMap 的使用上,大多数都是用来进行一些必要的逻辑判断的。在 WeakMap 实例上对已知对象的引用,从而在需要使用时,对该对象进行必要的逻辑判断。


联系我
置顶