当你面试被问到:请你说说对JS强引用和弱引用的理解
前言
今天在学习es6的时候,看到了WeakSet
和WeakMap
这两种数据结构,发现这两种数据结构对对象的引用方式为弱引用,下面来聊聊强引用与弱引用之间的区别。
强引用
JavaScript中,如果将一个对象用变量或常量保存时,那么这个变量或常量则称之为对该对象的强引用
。在JavaScript引擎中,可以理解为有一个指针从变量指向那个引用地址,如果该地址被指向,那么这个引用就不会被JS垃圾回收机制当作“垃圾”回收掉。而如果我们又将该引用分配给了一个新的变量,那么在栈内存当中,又会为这个新变量和该引用创建一个新的指针使他们连接在一起。
let user = { name: "张三" }
let user2 = user
在上面这段代码中,将引用{name:"张三"}
赋值给了user,这个操作在计算机内部会存在这样一个过程:
- 堆区中创建对象
{name:"张三"}
- 栈区中创建变量
user
指向堆区中的对象{name:"张三"}
- 然后又创建一个变量
user2
,并将user赋值给user2,在这里的赋值其实是将user
的引用地址赋给user2
,使得user
和user2
同时指向堆区的{name : "张三"}
上述过程则为JS中对象强引用,接下来我们来看看在ES6中的
WeakSet
和WeakMap
存储弱引用值时是怎么处理的。
弱引用
在ES6中引入了WeakSet
和WeakMap
两种类型,但它们只接受对象作为其元素,并且对这些对象保持弱引用。这意味着如果一个对象仅被WeakSet
或WeakMap
引用,即使WeakSet
或WeakMap
仍然保持对它的引用,它也可以被垃圾回收。
下面我将以WeakSet
为例为大家介绍弱引用的特性。看以下代码:
let user = { name: "张三" }
let user2 = user
// 来创建一个WeakSet实例
const ws = new WeakSet()
// 为实例ws添加一个数据:user2
ws.add(user2)
console.log(ws.has(user2))
在这段代码中,我们做了以下操作:
- 创建变量user,user2强引用同一个对象{name:"张三"}
- 创建WeakSet实例弱引用对象{name:"张三"}
上述过程在计算机内部可用下图表示:
可以看到,变量
user
,user2
直接指向对象{name:"张三"}
,而在ws
中对{name:"张三"}
的弱引用可以理解为是虚线指向。那么通过上述示例,我们可以这样理解强引用和弱引用之间的区别。一句话概括就是在JS的V8引擎中,强引用与对象之间存在一种强效的连接,而弱引用与对象之间的连接并不被V8引擎所认可
。在上述例子中,也就是说弱引用并不知道自己被ws
实例所引用,此时垃圾回收机制也不知道该引用被ws
实例所引用。那么在此时如果所有的对{name:"张三"}
的强引用消失时,那么该引用就会被js垃圾回收机制销毁,即使ws
还存在对该对象的引用。
看如下代码示例:
let user = { name: "张三" }
let user2 = user
// 来创建一个WeakSet实例
const ws = new WeakSet()
// 为实例ws添加一个数据:user2
ws.add(user2)
console.log(ws.has(user2))
user = null
user2 = null
console.log(ws.has(user2))
我们修改user
和user2
对{name:"张三"}
的引用为null
(或者指向其他位置)时,此时可以理解为user
、user2
与{name:"张三"}
之间的强效连接断开,那么这个时候ws
中对{name:"张三"}
的引用会发生什么呢?
请看以下图示:
这时user
、user2
对{name:"张三"}
的强引用全部断开,此时{name:"张三"}
不存在其他的强引用,即使在ws
中仍然存在对{name:"张三的"}
的弱引用,垃圾回收机制也会认为{name:"张三"}
不需要了将它销毁。
WeakMap
的弱引用方式也和上述WeakSet
的机制一样,这里就不赘述了。
本篇文章就到此为止啦,希望通过这篇文章能对你理解JS弱引用有所帮助
有所帮助,本人水平有限难免会有纰漏,欢迎大家指正。如觉得这篇文章对你有帮助的话,欢迎点赞收藏加关注,感谢支持🌹🌹。
转载自:https://juejin.cn/post/7373588614846808074