【ES6】聊聊ES6中新增的两种”引用数据类型“ Set - Map 以及面试热考点”弱引用集合“之Weakset

引言

【ES6】聊聊ES6中JS新增的两种"原始数据类型"及"类型判断"的四种方法(2)

在上篇文章中我们聊到了ES6新增的两种原始数据类型及其特性,今天我们来聊聊ES6新增的两种引用数据类型SetMap以及setWeakSet之间的区别。SetMap的出现为 JavaScript 中的数据存储和处理提供了更多灵活和高效的选择,特别是在需要存储唯一值或者键值对的情况下。引入这两种数据结构丰富了 JavaScript 的语言特性,使得开发者能够更方便地处理各种数据结构的需求。下面我会为大家详细介绍SetMap这两种数据结构以及为大家分析SetWeakset的区别。

迭代器(Iterator)

在讲这两种数据结构之前我们需要引入一个迭代器(Iterator)概念

概念

在JavaScript中,迭代器(Iterator)是一种对象,它提供了一种统一的方式来遍历数据结构中的元素,比如数组SetMap等。

实际上,许多内置数据结构都实现了迭代器接口,使得它们可以使用相同的方式进行遍历操作。你可以使用for...of循环或者调用迭代器对象的next方法来遍历这些数据结构,这里我们用for...of循环来判断该数据类型是否具有迭代器接口属性。

for...of循环遍历

在JavaScript中,for...of循环提供了一种便捷的方式来遍历可迭代对象(iterable),比如数组SetMap等。它相对于传统的for循环和forEach方法来说,语法更加简洁,同时可以处理各种不同类型的数据结构。如果一个数据结构拥有迭代器这个接口,也就是说明这个数据结构是能被for...of遍历的。

示例

js 复制代码
let arr = [1, 2, 3, 4];
for (let element of arr) {
  console.log(element);// 1 2 3 4
}

在这个示例中,for...of循环会迭代数组arr中的每一个元素,并将当前元素赋值给变量element,然后执行循环体内的代码。因为数组是拥有迭代器这个接口的,所以我们可以用for...of来对其循环遍历。

除了数组,我们也可以使用for...of循环来遍历其他可迭代对象,比如SetMap

js 复制代码
let mySet = new Set([1, 2, 3, 4]);
for (let value of mySet) {
  console.log(value);
}

let myMap = new Map([['a', 1], ['b', 2]]);
for (let [key, value] of myMap) {
  console.log(key, value);
}

需要注意的是,for...of循环只能用于可迭代对象,如果你想要遍历普通的对象(object),你可以使用for...in循环来实现。此外,for...of循环在遍历时会自动调用对象的迭代器(如果对象有的话),因此它非常适合用于处理可迭代对象的情况。

总的来说,for...of循环为JavaScript中的可迭代对象提供了一种简洁而统一的遍历方式,使得我们可以更加方便地处理各种类型的数据结构

Set

JavaScript中的Set是一种数据结构,用于存储不重复的值。它类似于数组,但与数组不同的是,Set中的元素不能重复出现。这意味着在Set中添加相同的值只会保留一个,我们称Set创建的对象为类数组。

js 复制代码
let arr = [1,1,2,3,3]
console.log(arr)
let set = new Set([1,1,2,3,3])
console.log(set)

我们在浏览器中打印这段代码,从执行的结果我们可以看出数组set的区别和相似之处,他们都是以数组形式输出结果,但是Set输出的结果中并没有重复项,而且Set可以被遍历输出就说明它也拥有迭代器这个接口属性。

我们在浏览器中声明一个Set类型的变量,并打印该对象,可以看到这个对象拥有的属性和其隐式原型内的方法,首先其拥有size属性,则说明我们可以往其中手动添加值,并且在下面我们会对这些常用方法进行举例说明。

Set中的 key 和 values 方法

在JavaScript中,Set对象提供了一些方法来获取其成员的键(keys)值(values)。然而,需要指出的是,由于Set是一种集合类型,它没有键值对的概念,因此在Set值是相同的,这是我们可以将键值对中的:和键值省略只写一个键值。不过,Set对象仍提供了keys()和values()方法,这两个方法的作用是相同的,都是用来返回Set对象中的值。

下面我来为大家分别介绍一下keys()和values()方法:

  1. keys()方法:Set对象的keys()方法返回一个新的迭代器对象,包含了Set对象中的所有值,顺序与插入顺序一致。
js 复制代码
let mySet = new Set(['a', 'b', 'c']);
let keysIter = mySet.keys();

for (let key of keysIter) {
  console.log(key);
}
// 输出:
// a
// b
// c
  1. values()方法:values()方法与keys()方法类似,也返回一个新的迭代器对象,包含了Set对象中的所有值。
js 复制代码
let mySet = new Set(['a', 'b', 'c']);
let valuesIter = mySet.values();

for (let value of valuesIter) {
  console.log(value);
}
// 输出:
// a
// b
// c

需要注意的是,由于Set对象中的键和值是相同的,因此无论是使用keys()方法还是values()方法,它们都会返回Set对象中的值。这与Map对象的keys()values()方法有所不同,因为Map对象中的键和值是分开存储的。

总的来说,使用keys()values()方法可以方便地遍历Set对象中的值,尤其适用于需要对集合中的值进行处理的情况。

Set中的 add 和 delete 方法

在 JavaScript 中,Set 对象提供了 add()delete() 方法,用于向 Set添加新元素和删除现有元素。

  1. add() 方法:add() 方法用于向 Set 中添加新元素。如果添加的值在 Set 中已经存在,则 Set 不会发生改变。
js 复制代码
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(3);

console.log(mySet); // 输出: Set { 1, 2, 3 }
  1. delete() 方法:delete() 方法用于从 Set 中删除指定的元素。如果 Set 中存在该元素,则它将被移除并返回 true;如果不存在,则返回 false
js 复制代码
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(3);

console.log(mySet); // 输出: Set { 1, 2, 3 }

mySet.delete(2);
console.log(mySet); // 输出: Set { 1, 3 }

需要注意的是,add() 方法返回的是 Set 对象本身,因此可以进行链式调用。而 delete()方法则返回一个布尔值,指示是否成功删除了指定的元素。

这些方法使得在 Set 对象中添加删除元素变得非常便捷,可以方便地维护集合的内容。

Set中的 clear 和 has 方法

在 JavaScript 中,Set 对象还提供了 clear()has() 方法,用于清空 Set 中的所有元素以及检查指定元素是否存在。

  1. clear() 方法:clear() 方法用于清空 Set 中的所有元素,使得 Set 变为空集。
javascript 复制代码
let mySet = new Set([1, 2, 3]);
console.log(mySet); // 输出: Set { 1, 2, 3 }

mySet.clear();
console.log(mySet); // 输出: Set {}
  1. has() 方法:has() 方法用于检查 Set 中是否包含指定的元素。如果 Set 中包含该元素,则返回 true;否则返回 false
javascript 复制代码
let mySet = new Set([1, 2, 3]);

console.log(mySet.has(2)); // 输出: true
console.log(mySet.has(4)); // 输出: false

这两个方法可以方便地管理 Set 对象中的元素。clear() 方法可以在需要时快速清空集合,而 has() 方法则可以帮助我们检查指定元素是否存在于集合中。

Set中的size方法

在 JavaScript 中,Set 对象中的 size 属性用于获取 Set 实例中元素的数量,即 Set 的大小。

下面是一个简单的示例:

javascript 复制代码
let mySet = new Set([1, 2, 3, 4, 5]);
console.log(mySet.size); // 输出: 5

在上面的示例中,mySet 是一个包含 1 到 5 的 Set 对象,并且通过访问 size 属性可以知道该对象包含了多少个元素。

size 属性提供了一种方便的方式来获取 Set 对象的大小,而无需像数组那样使用 length 属性。

Map

在 JavaScript 中,Map 是一种新的数据结构,用于存储键值对。它提供了一种更灵活的方式来存储和操作数据,相比于普通的对象Map 对象具有以下特点:

  1. 键的类型不限于字符串,可以是任意数据类型,甚至是对象、函数等。
  2. Map 对象中的元素是有序的,可以通过迭代器遍历,而对象的属性则没有固定的顺序。
  3. Map 对象的 size 属性可以获取键值对的数量,方便进行统计和管理。

下面是 Map 对象常用的方法:

  1. set(key, value) 方法:向 Map 中添加或更新指定键的值。
javascript 复制代码
let myMap = new Map();
myMap.set('name', 'Alice');
myMap.set(1, 'One');
console.log(myMap)//Map(2) {size: 2, name => Alice, 1 => One}
  1. get(key) 方法:获取指定键的值。
javascript 复制代码
console.log(myMap.get('name')); // 输出: Alice
console.log(myMap.get(1)); // 输出: One
  1. has(key) 方法:检查 Map 中是否包含指定的键。
javascript 复制代码
console.log(myMap.has('name')); // 输出: true
console.log(myMap.has('age')); // 输出: false
  1. delete(key) 方法:从 Map 中删除指定键及其对应的值。
javascript 复制代码
myMap.delete('name');
console.log(myMap.has('name')); // 输出: false
  1. clear() 方法:清空 Map 中的所有键值对。
javascript 复制代码
myMap.clear();
console.log(myMap.size); // 输出: 0

这些方法使得在 Map 对象中添加获取删除元素变得非常便捷,同时也提供了对键值对进行有效管理的能力。

弱引用集合:WeakSet

JavaScript 是一门灵活且动态的编程语言,其生态系统中不断涌现出新的特性数据结构。其中之一就是 ECMAScript 6(ES6)引入的 WeakSet,它为开发者提供了一种存储对象引用的集合方式,具有弱引用的特性。

弱引用的概念

在理解 WeakSet 之前,我们首先需要了解什么是弱引用。在 JavaScript 中,当我们创建一个对象并将其赋值给一个变量时,这个变量会持有该对象的引用。只要有变量持有着对对象的引用,对象就不会被垃圾回收

弱引用与之不同,它不会阻止对象被垃圾回收。如果一个对象只被弱引用持有,而在程序的其他地方没有其他引用指向它,这个对象就会被垃圾回收。这为解决内存泄漏问题提供了一种机制。

弱引用集合:WeakSet 的特性

WeakSet 就是利用了弱引用的概念,它是一种集合,专门用于存储对象引用。下面是一些关于 WeakSet 的重要特性:

1. 弱引用存储

WeakSet 中存储的对象是弱引用的,不会阻止这些对象被垃圾回收。这意味着当程序中没有其他地方引用这个对象时,它会被自动从 WeakSet 中移除。

2. 只能存储对象

WeakSet 只能存储对象引用,而不能存储原始值。这是因为原始值没有被垃圾回收的概念,弱引用对于原始值没有意义。

3. 不可迭代

由于弱引用的特性,WeakSet 是不可迭代的。因此,不能使用 forEach 等迭代方法直接访问其中的元素。

4. 没有 size 属性和 clear 方法

由于 WeakSet 不可迭代,因此没有类似 size 属性和 clear 方法的属性和方法。我们无法直接获取 WeakSet 中元素的数量。

5. 没有键名和值之分

WeakSet 只关心对象引用的存在与否,不关心键名和值的区别。只要对象引用存在,就被视为存在于 WeakSet 中。

使用示例

下面是一个简单的示例,演示了如何使用 WeakSet

js 复制代码
// 创建一个 WeakSet
let weakSet = new WeakSet();

// 创建一些对象
let obj1 = { name: 'Object 1' };
let obj2 = { name: 'Object 2' };
let obj3 = { name: 'Object 3' };

// 将对象添加到 WeakSet 中
weakSet.add(obj1);
weakSet.add(obj2);

// 检查对象是否存在于 WeakSet 中
console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj3)); // false

// 从 WeakSet 中删除对象
weakSet.delete(obj1);

// 检查对象是否存在于 WeakSet 中(删除后应为 false)
console.log(weakSet.has(obj1)); // false

在实际应用中,WeakSet 主要用于需要存储对象集合且不想阻止这些对象被垃圾回收的场景。它为开发者提供了一种灵活而高效的方式来处理对象引用,从而更好地管理内存和避免潜在的内存泄漏问题。

简单聊下垃圾回收机制

我们知道JavaScript预编译时会在调用栈中创建全局执行上下文函数执行上下文,而对象的存储是在中,如果这个执行上下文执行完毕了,垃圾回收机制一旦生效那么这个执行上下文就会被移出调用栈或者,用WeakSet声明的对象就是弱引用类型,垃圾回收机制一旦生效,这个对象里面的属性就都没了,也就是被垃圾回收机制清除了,但是当我们去浏览器中立即检查该对象中的属性时还能看见,这个问题曾一度被推上讨论榜首,后来解释而知JavaScript中垃圾回收机制并不是每时每刻生效,我们并不知道机制何时生效,但是我们可以理解为当垃圾回收机制开始生效时,若引用类型的对象就会被垃圾回收机制回收。

总结

md 复制代码
# set
1. 是一种key和value相等的特殊对象
2. set 对象中的值是唯一的
3. 具有迭代器(iterator)属性

# map
1.  键的类型不限于字符串,可以是任意数据类型,甚至是对象、函数等。
1.  Map 对象中的元素是有序的,可以通过迭代器遍历,而对象的属性则没有固定的顺序。
1.  Map 对象的 size 属性可以获取键值对的数量,方便进行统计和管理。

# WeakSet && WeakMap
一个对象被 weakset 所引用,在垃圾回收机制的眼中该对象是没有被引用的,只要垃圾回收机制一生效,该对
象所占据的内存空间就会被销毁。

如果这篇文章感觉对你有用的话,给作者一点鼓励点个赞吧♥

作者在持续更新更多有用的干货中,关注➕收藏 Coding不迷茫

所有文章的源码,给作者的开源git仓库点个收藏吧: gitee.com/cheng-bingw...

更多干货内容:【ES6】聊聊ES6中JS新增的两种"原始数据类型"及"类型判断"的四种方法(2)

相关推荐
谁呛我名字1 小时前
大数据应用开发——数据可视化
javascript·vue.js·echarts
前端郭德纲1 小时前
浅谈React的虚拟DOM
前端·javascript·react.js
2401_879103682 小时前
24.11.10 css
前端·css
ComPDFKit3 小时前
使用 PDF API 合并 PDF 文件
前端·javascript·macos
yqcoder3 小时前
react 中 memo 模块作用
前端·javascript·react.js
谈谈叭4 小时前
Javascript中的深浅拷贝以及实现方法
开发语言·javascript·ecmascript
优雅永不过时·4 小时前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
爱编程的鱼5 小时前
javascript用来干嘛的?赋予网站灵魂的语言
开发语言·javascript·ecmascript
神夜大侠6 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱6 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js