前言
JavaScript是一种高级的、基于事件驱动的编程语言,它的垃圾回收机制是自动管理内存的关键组成部分。并且在ES6(ECMAScript 2015)中引入了WeakSet
和WeakMap
这两个数据结构,它们为开发者提供了更灵活的内存管理方式,特别是在涉及到临时对象引用和垃圾回收方面。
今天,我们来潜聊一下JavaScript的垃圾回收机制和WeakSet
和WeakMap
在前文:【ES6干货】带你手把手学习js中的Set和Map!! - 掘金 (juejin.cn)已经为大家介绍了ES6+Set和Map的相关知识。大家感兴趣的话可以去学习一下!
垃圾回收机制
垃圾回收是一种自动管理内存的机制,通过检测不再被引用的对象,并将其释放,以防止内存泄漏。在JavaScript中,最常见的垃圾回收方式是基于引用计数和标记清除。引用计数是通过跟踪引用对象的次数来确定何时释放内存。标记清除则是通过标记不再需要的对象,然后清除它们。
不知道大家以前有没有接触过其他编程语言!在传统的编程语言当中,垃圾回收机制是不会自动执行的,需要我们程序员自己进行手动 分配和释放内存,这样容易导致内存泄漏和悬空指针等等人为的失误。所以在JavaScript中,为了避免这些问题,采取了一种自动垃圾回收的机制!
垃圾回收机制的工作原理:垃圾回收机制的主要目标是找到并释放不再被程序使用的内存。
- 引用计数: 这是一种简单的垃圾回收算法,它通过在内存中跟踪对象的引用次数来确定何时释放对象。当引用次数变为零时,说明对象不再被使用,可以安全地被回收。
- 标记清除: 这是一种更复杂但更普遍的垃圾回收算法。它从一组根对象开始,标记所有可以访问到的对象。然后,它清除未被标记的对象,因为它们不再可达。
在JavaScript中,垃圾回收机制主要依赖于标记清除算法,也就是我们上面所说的第二种方法,我们的JavaScript系统会自己周期性地执行垃圾回收操作,找到不再被引用的对象并释放它们占用的内存,也就意味着,这个周期性地执行并不受我们控制!而由编译系统自己决定!
我们通过这样一个案例来了解一下JavaScript中的垃圾回收机制
js
// 例子:垃圾回收的示意
let obj1 = { name: '小美' };
let obj2 = { name: '张三' };
obj1 = null; // 此时obj1不再引用任何对象
// 在垃圾回收周期中,obj1引用的对象将被标记为可回收
也就是说!我们可以通过将一个对象Obj = null
让Obj
不在引用任何对象,也就意味着:我们现在把Obj
标记为可清理,可回收的状态,那么,下次垃圾回收机制再次运行的时候,则会自动地释放掉Obj
的内存。
WeakSet: 弱引用的集合
接下来,我们来学习一下WeakSet
WeakSet
是一种集合,其中的元素只能是对象和Symbol
,并且这些对象是弱引用的。这意味着,如果一个对象只被WeakSet
引用,而没有被其他强引用引用,那么这个对象将被垃圾回收。
WeakSet
其实与Set
比较类似,都是不重复的集合!
我们来看看这个案例:
js
let weakset = new WeakSet();
var obj = new Object()
weakset.add(obj)//不报错
weakset.add(Symbol())//不报错
weakset.add(1)//报错
在这个案例当中,我们可以看到WeakSet()
中只能存储对象和Symbol
如果是其他数据类型都会报错!
说WeakSet
是弱引用?什么意思呢?意思就是:垃圾回收机制不会考虑WeakSet
对该对象的引用,如果没有其他对象引用这个对象,垃圾回收机制就会一点面子不给WeakSet
将它回收掉!
具体我们来看一个案例
js
let obj = {name:'亚索'}
let ws = new WeakSet()//只能存symbol和对象
ws.add(obj)
//浏览器的垃圾机制是不受我们掌控的,我们不知道什么时候会把它回收掉,垃圾回收机制的执行机时间是不受我们掌控的
//如果,下面没有有效应用,obj就会被销毁
console.log(ws);//输出:WeakSet { <items unknown> }
同时,WeakSet
中引用的对象,也会随着这个对象的销毁而销毁!也就是说,如果我们人为地去销毁那个对象的话!那么WeakSet
中的这个对象也会不复存在!!我们来看看这个案例!
javascript
let weakSet = new WeakSet();
let obj = {};
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
// 当对象被销毁后,WeakSet 也会自动删除对应的引用
obj = null;
console.log(weakSet.has(obj)); // false
WeakSet
常用于存储一组对象,而不需要担心这些对象是否还存在于其他地方。它对于缓存和临时数据存储非常有用。
WeakSet的方法
1. add(value):
add
方法用于在 WeakSet
中添加新的元素。
js
let weakSet = new WeakSet();
let obj = {};
weakSet.add(obj);
2. has(value):
has
方法用于检查 WeakSet
中是否存在特定元素。
js
console.log(weakSet.has(obj)); // true
3. delete(value):
delete
方法用于从 WeakSet
中删除特定元素。
js
weakSet.delete(obj);
console.log(weakSet.has(obj)); // false
注意事项:
WeakSet
没有迭代方法,因此不能使用forEach
和for ...of
进行遍历。- 由于元素是弱引用的,如果没有其他强引用指向元素,
WeakSet
在垃圾回收时会自动清理不再被引用的元素。
WeakMap: 弱引用的键值对集合
WeakMap
是一种键值对的集合,其中的键是弱引用的。与WeakSet
类似,如果一个对象只被WeakMap
引用,而没有被其他强引用引用,那么这个对象将被垃圾回收。
同时,WeakMap
只能存储对象和Symbol
,这一点其实与WeakSet
相同!
js
let weakmap = new WeakMap();
var obj = new Object()
weakmap.set(obj,12)//不报错
weakmap.add(Symbol(),45)//不报错
weakmap.add(1,1)//报错
weakmap.add(null,1)//报错
WeakMap
的存储解构和Map
相同!但是WeakMap
的key
值只能是对象和Symbol
,否则就会报错!
同样的,WeakMap
也是弱引用!垃圾回收机制不会考虑WeakMap
对该对象的引用,如果没有其他对象引用这个对象,垃圾回收机制就会一点面子不给WeakMap
将它回收掉!
在垃圾回收机制前面WeakMap
和WeakSet
就是两个难兄难弟!
我们来看一个案例!
js
let obj = {name:'锐雯'}
let wm = new WeakMap()
console.log(wm.set(obj,5));//输出:WeakMap { <items unknown> }
作为两个难兄难弟,WeakMap
和WeaSet
一样一样的"卑微",WeakMap
中引用的对象,也会随着这个对象的销毁而销毁!!
javascript
let weakMap = new WeakMap();
let key = {};
let value = '你好';
weakMap.set(key, value);
console.log(weakMap.has(key)); // 输出:true
console.log(weakMap.get(key)); // 输出:'你好'
// 当键对象被销毁后,WeakMap 也会自动删除对应的键值对
key = null;
console.log(weakMap.has(key)); // 输出:false
console.log(weakMap.get(key)); // 输出:undefined
WeakMap
通常用于将一些数据与特定对象关联,而无需担心这些数据会阻止对象被垃圾回收。它在处理私有数据和缓存方面非常有用。
WeakMap的方法
1. set(key, value):
set
方法用于向WeakMap
中添加键值对。
js
let weakMap = new WeakMap();
let key = {};
let value = 'Some value';
weakMap.set(key, value);
2. get(key):
get
方法用于获取指定键对应的值。
js
console.log(weakMap.get(key)); // 'Some value'
3. has(key):
has
方法用于检查WeakMap
中是否存在特定键。
js
console.log(weakMap.has(key)); // true
4. delete(key):
delete
方法用于从WeakMap
中删除指定键值对。
js
weakMap.delete(key);
console.log(weakMap.has(key)); // false
注意事项:
WeakMap
不支持迭代方法(如forEach
),因为弱引用的键不允许直接遍历。- 由于键是弱引用的,如果没有其他强引用指向键,
WeakMap
在垃圾回收时会自动清理不再被引用的键值对。 WeakMap
的方法相对较少,主要是因为其设计目的是提供一种不会阻止垃圾回收的弱引用集合。
WeakMap
主要用于在需要与对象关联信息但又不希望干扰垃圾回收的情况下使用,例如存储对象的私有数据。弱引用的特性使得WeakMap
在这些情况下更为合适。
总结
在JavaScript中,垃圾回收机制是确保应用程序高效运行的重要组成部分。垃圾回收机制通过自动管理内存,避免了手动内存管理的复杂性和错误,就像是一个自动扫地机器人一样,自动地为我们清理内存,这不仅提高了开发效率、降低了内存泄漏的风险,还能够增强我们写的代码的可维护性和健壮性。
同时呢:WeakSet
和WeakMap
为开发者提供了更灵活的内存管理方式,特别是在处理临时数据、私有数据以及避免内存泄漏方面。
大家感兴趣的可以去深入学习和理解一下这WeakSet
和WeakMap
的相关知识,这有有助于我们提高代码的性能和可维护性。
对于 WeakSet
和WeakMap
,我们可以知道如下:
-
避免内存泄漏:
WeakSet
和WeakMap
的弱引用特性有助于防止因为对象被引用而无法被垃圾回收,从而减少内存泄漏的风险。 -
临时数据存储: 这两种数据结构非常适合存储一些临时性的数据,因为它们会随着对象的销毁而自动清理。
-
私有数据管理:
WeakMap
常被用于存储与对象关联的私有数据,因为这样的数据不会影响垃圾回收。 -
不可迭代: 由于弱引用的特性,
WeakSet
和WeakMap
不可迭代,即不能通过循环获取其中的所有元素或键值对。
好啦!我们今天的学习就到这里为止啦!
大家有任何想法欢迎大家评论哦~
点个小赞鼓励支持一下吧!🌹🌹🌹