Skip to content
字数
1123 字
阅读时间
5 分钟

强引用和弱引用

从 1 套代码结合两张图来理解

对于强引用

js
const myMap = new Map()
let my = {
    name: "ljc",
    sex: "男"
}
myMap.set(my, 'info');
console.log(myMap);

image-20210725161643051

对于弱引用

js
const myMap = new WeakMap()
let my = {
    name: "ljc",
    sex: "男"
}
myMap.set(my, 'info');
console.log(myMap);

image-20210725161619701

图一中的数据被 mymyMap 实例对象所引用,引用计数为 2,图 2 中建立了 myMapmy 所引用的对象的弱引用,引用计数为 1

在上面我们谈到强引用数据被删除时,需要手动解除引用,而弱引用则可以等待垃圾回收机制自动清除

weaMap

WeakMap 保持了对键名所引用的对象的弱引用,即垃圾回收机制不将该引用考虑在内

只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存

WeakMap 的使用场景

DOM 节点元数据

用红宝书的例子

因为 weakMap 不会影响垃圾回收,所以可以用来关联元数据

image-20210725171056590

当上面代码执行后,登录按钮从 DOM 树中被删除了,但由于 Map 对节点对象是强引用关系,仍然保存着对按钮的引用,所以会引起内存泄漏

image-20210725171352098

因此可以采用 WeakMap 当节点删除后,引用计数为 0,等待垃圾回收机制回收

WeakMap 部署私有属性

Map 和 WeakMap 都可以部署私有属性,只是前者存在内存泄露的问题,而后者因为弱引用的特性会随着实例的消失,私有属性也会消失

javascript
// const privateData = new Map();
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;
    }
}

const person = new Person('x', 12)
const person2 = new Person('y', 21)

console.log(person.getName())
console.log(person2.getName())

数据缓存

当我们需要在不修改原有对象的情况下储存某些属性等,而又不想管理这些数据时,可以使用 WeakMap
image-20210725173257029

针对 const 的意义

主要保护引用不被修改 (如用 Map 等接口对引用的变化很敏感 (使用 WeakMap 的时候,外部用 const 定义一个对 map 中某个值的引用,可以防止这个值被 gc

查找和遍历的性能方面

Map 优于 WeakMap

在查找方面,由于 WeakMap 的键是弱引用,它的查找效率要比 Map 低一些。因为在 WeakMap 中,需要通过键对象的哈希值去查找键值对,然后再判断键对象是否存在,这个过程会增加查找时间。

在遍历方面,Map 是一种可以迭代的数据结构,可以通过 for...of 等语句进行遍历。而 WeakMap 由于键对象的弱引用,无法遍历键对象。因此,WeakMap 内部只能使用迭代器模式,通过 Map 的实例进行遍历

查找的原理

虽然 WeakMapMap 都是基于哈希表实现的,但它们的实现方式不同。

Map 会对键值对的键进行哈希,然后将其存储在内部的存储桶中。在查找键时,首先会将键哈希为一个桶号,然后查找该桶中是否有与其匹配的键值对。如果桶中有多个键值对,则需要按照某种方式来处理哈希冲突。因此,在大部分情况下,Map 的查找速度非常快。

WeakMap 的实现方式略有不同。由于键是弱引用,WeakMap 内部存储的是键的地址的引用(即弱引用)。在查找键时,WeakMap 会将键转换成内部的地址引用,然后在内部的存储桶中查找该地址引用是否存在。因为 WeakMap 的键是弱引用,所以当键的引用被垃圾回收时,与之相关联的键值对也会被自动移除,从而避免了内存泄漏。但是由于 WeakMap 内部需要维护引用,所以在查找和遍历时,相对于 Map 会有一些性能上的损失。

参考

浅析 Map 和 WeakMap 区别以及使用场景 - 掘金

贡献者

The avatar of contributor named as jiechen jiechen

页面历史

撰写