强引用与弱引用

103 阅读3分钟

理解强引用

let cat = { name: "Kitty" };
const pets = [cat];

cat = null;
console.log(pets); // [ { name: 'Kitty' } ]

通过将变量 cat 创建为对象,并把这个对象放入一个数组 pets 中,然后通过将它的值设置为 null 来删除其对原始对象的引用

尽管我们再也无法访问 cat 变量,但由于在 pets 数组和这个对象之间存在强引用关系,因此这个对象其实仍保留在内存中,并且可以通过 pets[0] 访问到它。 换句话说,强引用可以防止垃圾回收从内存中删除对象

理解弱引用

let pets = new WeakMap();
let cat = { name: "Kitty" };
pets.set(cat, "Kitty");
cat = null;

console.log(pets.get(cat)); // undefined

当我们通过将 cat 变量重新赋值 null 来覆盖对原始 cat 对象的引用时,由于内存中对原始对象的唯一引用是来自我们创建的 WeakMap 的弱引用,所以它不会阻止垃圾回收的发生。这意味着当 JavaScript 引擎再次运行垃圾回收过程时,cat 对象将从内存和我们分配给它的

可以用一个简单的例子来形容强引用弱引用

强引用:A牵着一条狗,他们之间通过狗链连着

弱引用:B指着A牵的狗,说:嘿,那有条狗,B指向那条狗,但他们之间没有是绑在一起的东西

当A放开狗链,无论B是不是还指着,狗都会跑掉(被垃圾回收器回收)

当B不再指着那条狗,狗还被A牵着,不会影响它是否跑掉

因此这里的关键区别就在于,强引用可以防止对象进行垃圾回收,而弱引用则不会

默认情况下,JavaScript 对其所有引用使用强引用,使用弱引用的唯一方法是使用 WeakMap 或 WeakSet

WeakMap

WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。但是 WeakMap 只接受对象作为键名( null 除外),不接受其他类型的值作为键名

设计目的

1、有时想在某个对象上存放一些数据,但是这会形成对于这个对象的引用。一旦不再需要这两个对象,就必须手动删除这个引用,否则垃圾回收机制就不会是的对象占用的内存。

2、而WeakMap的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只需要引用的对象的其他引用都被清除,垃圾回收机制就会释放的该对象所占用的内存。也就是说,一旦不再需要,WeakMap里面的键名和所对应的键值对会自动消失,不用手动删除引用。

WeakMap与Map的区别

Map:

let map = new Map();
let cat = { name: "Kitty" };
map.set(cat,'dog')
cat = null;

console.log(map); // Map { { name: 'Kitty' } => 'dog' }

WeakMap:

let wm = new WeakMap();
let cat = { name: "dog" };
wm.set(cat, "dog");
cat = null;

console.log(wm); // WeakMap {  }
  • Map的键可以是任意类型,WeakMap只接受对象作为键,不接受其它类型的值作为键

  • WeakMap的键名所指向的对象,不计入垃圾回收机制(当出现WeakMap对对象的弱引用时,垃圾回收机制不会计入这个引用,也就是说,WeakMap对对象的引用不会妨碍原始对象被垃圾回收机制清除)

  • Map可以被遍历,WeakMap不能被遍历