聊一聊JS中WeakMap与WeakSet的渣男特性

269 阅读4分钟

我正在参与掘金创作者训练营第6期,点击了解活动详情

有一天,恶霸在实验室里卷代码,突然有一个学妹抱着电脑来找我,问我WeakMapWeakSetSetMap的主要区别是什么,这我就提起兴致了,趁这个机会给学妹普及一下渣男的性质

如果在看这篇文章之前不了解SetMap,那么请移步学习一下二者的特性,话不多说,开始我们的正题。

浅浅地了解一下垃圾回收机制(gc)

我问学妹,你知道垃圾回收是什么吗,她用无辜的眼神看着我,摇了摇头,由于要透彻地了解WeakMapWeakSet的渣男特性,于是我浅浅得给她讲了一下垃圾回收及内部机制。

垃圾回收是什么?

简单概括一下垃圾回收:当一个变量不会再被调用,就会被释放,之后垃圾回收就会周期性释放它占用的内存,它可以很好的帮助我们再代码执行阶段管理内存,减轻我们开发者的负担,当我们不再使用一个变量的时候,仅仅只需要a = null,a之前所引用的数据就会被释放,然后垃圾回收就会自动清理。

内部的原理

我看了眼学妹,她貌似懂了,那么可以精进一下,了解一下垃圾回收是怎么进行的

垃圾回收机制内部原理之一的引用计数字,一共分为三步

  1. 第一步:当一个变量被声明的时候计数为1
  2. 第二步:当这个变量被给到另外一个变量或者数据结构中,计数加1
  3. 第三步:当这个变量的引用在其他地方使用null或者其他变量引用覆盖后,计数-1
  4. 第四步:垃圾回收周期性自动将计数为0的变量回收

为了更好地理解这四步,我拿代码给学妹举例子

let a = "猪痞恶霸" // 声明计数为 1

let b = a // 赋值计数 +1 = 2

b = null // 覆盖释放计数 -1 = 1

a = null // 释放计数 -1 = 0

// 周期性执行垃圾回收

看完这个例子后,学妹清楚了垃圾回收的大概,下面我就要给她灌输WeakMapWeakSet的渣男特性。

WeakMap和WeakSet是什么

WeakMapWeakSet是ES6中新增的数据结构,其对应着SetMap,而仅仅在头部添加Weak一词就造就了其不同的特性,主要有如下几点

  • 只能接受对象作为键值
  • 无法使用clear方法
  • 弱映射的键
  • size属性且无法被遍历

那么WeakMapWeakSet渣男特性是什么呢?就是弱映射的键。 为什么说这个特性是渣男特性?观众老爷往后看!

细说渣男特性

弱映射的键其实是垃圾回收机制会忽略掉WeakMapWeakSet对于其他变量的引用。通俗来讲在变量被WeakMapWeakSet内引用的时候,垃圾回收内部进行的引用计数不会进行计数操作,这就会导致当其他对象不再引用WeakMap存储的对象时,WeakMap会自动释放,后被回收掉。

抽象地讲WeakMapWeakSet在找了一个女朋友后竟然不管她的死活,当女朋友再没有引用后不保护她,直接被垃圾回收掉,你说是不是渣男。

讲到这里,学妹破口大骂:渣男!我对学妹说,等一下再骂,我给你讲完的,于是我用代码给她举了个例子

let a = "猪痞恶霸" // 声明计数为 1

let zhanan = new WeakMap()

zhanan.set({
    a,a
}) // 垃圾回收机制忽略,计数不变为 1

a = null // 释放计数 -1 = 0

// 垃圾回收销毁

看完这个例子就在表层理解了垃圾回收忽略弱映射的键的特性,而这个特性会导致另外一个特性,无size属性且无法被遍历。

因为弱映射的特性,所以WeakMapWeakSet会随时释放,销毁,在遍历过程中可能会发生成员消失现象,所以无法对其进行遍历也无法获取其属性size

console.log(zhanan.size) // undefined

以抽象地形式讲完了WeakMap与WeakSet的弱映射特性,学妹也听懂了,于是我收拾书包准备和学妹吃饭去,而此刻一位学弟走来:学长你能给我讲一讲吗? 我:自己百度去。。。。