set和map你也许很清楚,那么weakset和weakmap你了解多少呢?

前言

最近在学习es6的时候,了解到了weakSet和weakMap这两种数据结构,并且发现了它们对对象的引用方式都为弱引用,那么什么是弱引用呢?是不是还有强引用呢?在给大家聊这个问题之前,咱们先来聊聊set和map身上的一些方法和知识点。

正文

Set

一、set实例的创建

ini 复制代码
const s = new Set();

二、set身上的方法

  1. add(value) : 向Set集合中添加一个元素。如果该值已存在,则不会重复添加。
  2. delete(value) : 从Set集合中删除指定的元素。如果元素存在并被成功删除,返回true;否则,返回false
  3. clear() : 清空Set集合中的所有元素。
  4. has(value) : 检查Set集合中是否包含指定的元素,返回一个布尔值。
  5. size : 属性而非方法,返回Set集合中元素的数量。
  6. values() , keys() , entries() : 这些方法用于获取集合中的元素。在Set中,由于每个元素都是键也是值,所以keys()values()返回相同的结果,而entries()返回的是键值对数组,每个键值对中键和值是相同的。
  7. forEach() : 对Set中的每个元素执行一次提供的函数。
  8. [Symbol.iterator] : 使Set可迭代,可以使用for...of循环遍历集合中的元素。

给大家来举个例子:

scss 复制代码
const s = new Set();
s.add(1);
s.add(2);

console.log(s);
console.log(s.keys()); // 键名
console.log(s.values()); // 值
console.log(s.entries()); // 键值对

可以看到在Set中,由于每个元素都是键也是值,所以keys()values()返回相同的结果,而entries()返回的是键值对数组,每个键值对中键和值是相同的。

三、set的遍历

咱们还可以通过传入数据的方法来初始化Set实例,用for...of对其进行遍历

javascript 复制代码
const s = new Set([1, 2, 3, 3]);
for (let item of s) { 
    console.log(item);
}

这里由于键名中有两个3,同属于一个键名,因此放入一个键名中。

四、可以使用[...new set(arr)]来对数组去重

操作如下:

ini 复制代码
const arr = [1, 2, 3, 4, 4, 3, 2, 1];
const arr2 = [...new Set(arr)];
console.log(arr2);

可以看到使用[...new set(arr)]可以去除数组中的重复元素。

Map

JavaScript中的Map对象是一种可存储键值对的数据结构,其中的键可以是任何值(包括对象)。

一、Map实例的创建

javascript 复制代码
const m = new Map(); // 可以用任意类型做key

二、Map身上带有的方法

  1. set(key, value) : 向Map中添加或设置键值对。如果键已经存在,则会更新对应的值。
  2. get(key) : 返回与指定键关联的值,如果不存在,则返回undefined
  3. has(key) : 判断Map中是否存在指定的键,返回布尔值。
  4. delete(key) : 删除与指定键关联的键值对,如果删除成功返回true,否则返回false
  5. clear() : 清空Map中的所有键值对。
  6. size : 属性,返回Map中键值对的数量。
  7. keys() : 返回一个新的迭代器对象,包含了Map中所有键的迭代器。
  8. values() : 返回一个新的迭代器对象,包含了Map中所有值的迭代器。
  9. entries() : 返回一个新的迭代器对象,包含了Map中所有键值对([key, value])的迭代器。
  10. forEach(callbackFn[, thisArg]) : 对Map中的每个键值对执行提供的函数。callbackFn接收三个参数:当前值、当前键和Map本身。
  11. [Symbol.iterator] : 使Map可迭代,可以用for...of循环遍历键值对。

它的遍历方法和set差不多,这里我就不在叙述啦,接下来跟大家聊聊weakSet和weakMap,以及js中的强引用和弱引用。

weakSet

JavaScript中的SetWeakSet都是用于存储唯一值的集合,但它们之间存在一些关键性的差异:

  1. 存储内容:

    Set: 可以存储任何类型的值,包括原始值(如字符串、数字)和对象引用。

    WeakSet : 只能存储对象引用,不能存储原始值。这意味着你不能在WeakSet中放入字符串、数字、布尔值等非对象类型。

  2. 引用强度:

    Set : 对其包含的元素保持强引用,这意味着只要Set存在,它所包含的元素就不会被垃圾回收,即使这些元素在其他地方没有引用。

    WeakSet : 对其包含的对象持有弱引用。这意味着如果对象在WeakSet之外没有其他引用,那么垃圾回收机制可以回收这些对象,即使它们还在WeakSet中。这有助于避免内存泄漏,特别是当用来跟踪临时的对象状态时。

  3. 迭代与大小:

    Set : 提供了size属性来获取集合的大小,并且可以使用forEachfor...of等方法来遍历集合中的所有元素。

    WeakSet : 没有size属性,也无法进行遍历操作(没有forEachkeysvaluesentries等方法)。这是因为它的设计目的是为了隐私和垃圾回收的便利,不允许外部直接访问其内部状态或元素。

  4. 方法集:

    Set : 提供了adddeletehasclear以及迭代方法。

    WeakSet : 只提供了adddeletehas方法,没有clear方法,因为无法遍历其内容来清除,因为弱引用的特性会自动处理不再被使用的对象。

第二点可能有点不太好理解,这里我给大家来解释一下第二点,

什么是强引用呢?

**强引用 **

表示变量对一个对象的直接持有。当一个对象被一个变量通过赋值方式引用时,就形成了对该对象的一个强引用。在v8引擎中,可以理解为有一个指针从变量指向那个引用地址,如果该地址被指向,那么这个引用就不会被JS垃圾回收机制当作"垃圾"回收掉。而如果我们又将该引用分配给了一个新的变量,那么在栈内存当中,又会为这个新变量和该引用创建一个新的指针使他们连接在一起。

给大家举个例子:

ini 复制代码
let user = { name: "张三" }
let user2 = user

在这个例子中,将引用{name:"张三"}赋值给了user,这个操作在v8引擎中会存在这样一个过程:

  1. 在堆中创建对象{name:"张三"}
  2. 在栈中创建变量user指向堆区中的对象{name:"张三"}
  3. 最后又创建一个变量user2,并将user赋值给user2,在这里的赋值其实是将user的引用地址赋给user2,使得useruser2同时指向堆区的{name : "张三"}

在上述过程中,对象被一个变量通过赋值方式引用时则为对象强引用。

什么是弱引用?

弱引用

是一种特殊类型的引用,它允许垃圾回收器在没有其他强引用存在的情况下回收被引用的对象,即使还有弱引用指向该对象。

咱们今天要聊的WeakSetWeakMap两种类型,就是典型的弱引用,它们只接受对象作为其元素,并且对这些对象保持弱引用。这意味着如果一个对象仅被WeakSetWeakMap引用,即使WeakSetWeakMap仍然保持对它的引用,它也可以被垃圾回收。

在给大家以weakset为例举个例子:

javascript 复制代码
let user = { name: "张三" }
let user2 = user
// 来创建一个WeakSet实例
const user3 = new WeakSet()
// 为实例user3添加一个数据:user2
user3.add(user2)
console.log(user3.has(user2))

咱们首先创建两个变量user,user2强引用同一个对象{name:"张三"},接着创建weakset实例弱引用对象{name:"张三"},同样是上面那个图,咱们可以理解为user3对{name:"张三"}的弱引用理解为虚线指向,在v8引擎中,强引用与对象之间存在一种强效的连接,而弱引用与对象之间的连接并不被V8所认可。也就是说弱引用并不知道自己被user3实例所引用,此时垃圾回收机制也不知道该引用被user3实例所引用。那么在此时如果所有的对{name:"张三"}的强引用消失时,那么该引用就会被js垃圾回收机制销毁,即使user3还存在对该对象的引用。

比如说咱们再将user和user2的引用改为null时:

ini 复制代码
let user = { name: "张三" }
let user2 = user
// 来创建一个WeakSet实例
const user3 = new WeakuserSet()
// 为实例user3添加一个数据:user2
user3.add(user2)
console.log(user3.has(user2))
user = null
user2 = null
console.log(user3.has(user2))

此时可以理解为useruser2{name:"张三"}之间的强效连接断开,那么这个时候user3中对{name:"张三"}的引用会发生什么呢?

这时useruser2{name:"张三"}的强引用全部断开,此时{name:"张三"}不存在其他的强引用,即使在user3中仍然存在对{name:"张三的"}的弱引用,垃圾回收机制也会认为{name:"张三"}不需要了而将它销毁。

WeakMap的弱引用方式也和WeakSet的方法一样,这里咱就不说啦

总结:

弱引用:

当它执行完后垃圾回收机制就会回收它,不管后面有没有其他引用指向它。

  1. 一个对象obj存放在了其他的结构中,当后续存在其他对象引用这个对象,那么这个对象的内存就不会被回收。
  2. 一个对象obj存放在了其他的结构中,当后续只存在WeakSet对它的引用,该对象的内存依然会被回收。

好啦,今天的分享就到这里啦,希望本文能对你理解强弱引用有新的帮助哈!可以留下一个免费的赞赞嘛 感谢感谢!

相关推荐
Apifox3 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95277 分钟前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿30 分钟前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼1 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187301 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下1 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox1 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞1 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行1 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758101 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox