ES6数据结构深度解析:Set, Map, WeakSet 和 WeakMap

Set和Map

Set和Map是ES6新增加的数据类型。其中Set被称作"集合",Map被称作"映射"。

新增的这两个数据结构提供了更灵活和强大的方式来处理和存储数据。

Set

Set是一个简单值的集合,类似于数组。Set的特点:Set成员的值都是唯一的,不允许重复。

通过Set这一特性,可以运用Set进行去重操作。

  1. 数组去重:

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

    结果为:

通过数组的解构和Set无重复值的特性,可以产生一个数组去重的小妙招。

  1. 字符串去重:

    javascript 复制代码
    const str = 'abcabcaaa'
    const newStr = [...new Set(str)].join('')
    console.log(newStr);

    结果为:

数组可以通过Set特性去重,而且数组还有join方法可以将数组转换成字符串,这样我们可以联想到字符串去重的方法。

Set常用方法

  1. 通过new Set()初始化Set对象:

    javascript 复制代码
    const set = new Set()
    
    //或从一个数组创建
    const arr = [1,2,3,4]
    const set = new Set(arr)
  2. 调用add(value)方法向 S集合 中添加指定元素:

    javascript 复制代码
    set.add(1)
  3. 调用has(value)方法检查集合中是否存在指定元素:

    javascript 复制代码
    set.has(2)
  4. 调用delete(value)方法删除集合中的指定元素:

    javascript 复制代码
    set.delete(1)
  5. 调用clear()方法清空集合内所有元素:

    javascript 复制代码
    set.clear()
  6. set对象中的size属性可以返回集合中元素的数量:

    javascript 复制代码
    set.add(1)
    set.add(1)
    console.log(set.size)//1(不存在重复值)

Set的遍历方法

  1. 调用keys()方法返回一个新的迭代器对象,该对象包含Set对象的每个元素的键。
  2. 调用values()方法返回一个新的迭代器对象,该对象包含Set对象的每个元素的值。
  3. 调用entries()方法返回一个新的迭代器对象,该对象包含Set对象的每个元素(值和键)。
javascript 复制代码
const set = new Set([1, 2, 3, 1, 2, 3, 4])
console.log(set.keys());
console.log(set.values());
console.log(set.entries());

结果为:

遍历Set的方法

  1. forEach方法:

    和数组一样,Set也有forEach方法。

    javascript 复制代码
    const set = new Set([1, 2, 3, 1, 2, 3, 4])
    set.forEach((item) => {
        console.log(item)
    })

    结果为:

  1. for...of循环:

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

    结果为:

Set的优缺点

  • 优点:
    1. Set中的元素都是唯一的,不会重复的值。
    2. 因为Set中的值是唯一的,所有查找、删除和添加的操作执行得更快。
  • 缺点:
    1. 在ES6中,Set保持了插入顺序,但是存在兼容问题。
    2. 与数组不同,Set不能通过索引来访问Set中的元素。

Map

在普通对象中,对象的键名的类型都是字符串,如果不是字符串类型也会被转换为字符串类型。eg:

javascript 复制代码
let n = 123
const obj = {
    [n]: 1,
    n: 1,
    name: '张三',
    [[]]: '1'
}
console.log(obj);

结果为:

都转换成了字符串类型。

然而随着需求的不断增加,出现了对象中的键名需要是其他类型的需求。因此JavaScript提供了Map这一数据结构。

Map这一数据结构允许使用任何值作为键。

注意:不要将数组的map方法和Map数据结构记混。

Map常用方法

  1. 通过new Map()初始化Map对象:

    javascript 复制代码
    const map= new Map()
  2. 调用set(key,value)方法向Map中添加一个键值对:

    javascript 复制代码
    map.set('name','张三')

    注意:不要和上面的Set数据结构搞混喽。

  3. 调用get(key)方法根据提供的键名返回对应的值,如果不存在该键名则返回undefined:

    javascript 复制代码
    map.get('name')
  4. 调用has(key)方法可以检查是否包含指定的键:

    javascript 复制代码
    console.log(map.has('name'))

    如果包含就返回true,如果不包含就返回false。

  5. 调用delete(key)方法可以删除指定的键值对:

    javascript 复制代码
    map.delete('name')
  6. 调用clear()方法可以删除所有键值对:

    javascript 复制代码
    map.clear()
  7. Map的属性size可以返回键值对数量。

Map的遍历方法

与Set的遍历方法相似。

  1. keys():返回一个新的迭代器对象,其中包含Map的所有键名。
  2. values():返回一个新的迭代器对象,其中包含Map的所有键值。
  3. entries():返回一个新的迭代器对象,其中包含Map的所有键值对。
javascript 复制代码
const map = new Map();
map.set('1', '2')
map.set(['1'], '1')
console.log(map.keys());
console.log(map.values());
console.log(map.entries());

结果为:

遍历Map的方法

  1. forEach方法:

    javascript 复制代码
    const map = new Map()
    map.set('name', '张三')
    map.set('age', 18)
    map.set('gender', '男')
    map.forEach((value, key) => {
        console.log(key, value)
    })

    结果为:

  1. for...of循环:

    javascript 复制代码
    const map = new Map()
    map.set('name', '张三')
    map.set('age', 18)
    map.set('gender', '男')
    for (let [key, value] of map) {
        console.log(key, value)
    }

    结果为:

Map的优缺点

  • 优点:
    • Map可以存储如何类型的键和值。
    • Map的键也是唯一的,不存在重复的键。
    • Map内的顺序和插入顺序一致。
  • 缺点:
    • 存在兼容问题。
    • Map不能和数组一样通过索引直接访问。

弱引用和强引用

WeakSet和WeakMap都是弱引用,首先了解一下什么是弱引用。

弱引用是不能确保其引用的对象不会被垃圾回收器回收的引用,而强引用是确保其引用的对象不会被垃圾回收器回收的引用。

也就是说,JavaScript引擎在执行代码时,对象通过变量直接赋值形成的引用会被视为强引用,垃圾回收器就不会回收这类对象;通过WeakMapWeakSet建立的引用会被视为弱引用,这类引用无法阻止垃圾回收器的回收。

当一个变量被设置为null时,会断开该变量与原对象间的引用,该对象就会变成垃圾回收器的回收目标。

eg:强引用

javascript 复制代码
let person = { name: "张三" };
const person1 = [person]; 
person = null; 
console.log(person1); 

创建一个叫person的对象,并将该对象存储到person1中;然后将person设置为null,断开引用,但是因为变量person1存在对person对象的强引用,所以该对象不会被垃圾回收器给盯上。

eg:弱引用

javascript 复制代码
let person1 = new WeakMap();
let person = { name: "张三" };
person1.set(person, "张三"); 
person = null; 
// 等待垃圾回收后 
console.log(person1); 

创建一个weakMap对象person1和一个对象person,并且将该对象作为键,键值为"张三"添加到person1中;然后将变量person设置为null,断开了变量与对象的引用,然而person1person是弱引用,所以垃圾回收器可以回收person对象。

WeakSet和WeakMap

WeakSet

WeakSet和Set非常相似,但是有一些不同之处:

  1. 成员类型:WeakSet的成员只能是Symbol值和对象,不能是其他的数据类型;Set的成员可以是任意数据类型。
  2. 引用类型:WeakSet是弱引用;Set是强引用。
  3. 方法和属性:WeakSet不支持迭代,所以没有forEach, values, keys, entries方法,并且也没有size属性;Set有forEach, values, keys, entries方法,也有size属性。
  4. 作用:WeakSet可以实现自动清理回收;Set可以通过元素的唯一性用于实现去重工作。

WeakMap

WeakMap和Map也非常相似,但是也是有一些不同:

  1. 键的类型:WeakMap的键类型只能是对象和Symbol值;Map的键类型可以是任意数据类型。
  2. 引用类型:WeakMap是弱引用;Map是强引用。
  3. 方法和属性:WeakMap不支持迭代,所以没有forEach, values, keys, entries方法,并且也没有size属性;Map有forEach, values, keys, entries方法,也有size属性。
  4. 作用:WeakMap也可以实现自动清理回收;Map提供需要高效键值对的操作。
相关推荐
10年前端老司机1 小时前
什么!纯前端也能识别图片中的文案、还支持100多个国家的语言
前端·javascript·vue.js
摸鱼仙人~1 小时前
React 性能优化实战指南:从理论到实践的完整攻略
前端·react.js·性能优化
程序员阿超的博客2 小时前
React动态渲染:如何用map循环渲染一个列表(List)
前端·react.js·前端框架
magic 2452 小时前
模拟 AJAX 提交 form 表单及请求头设置详解
前端·javascript·ajax
小小小小宇7 小时前
前端 Service Worker
前端
只喜欢赚钱的棉花没有糖7 小时前
http的缓存问题
前端·javascript·http
小小小小宇8 小时前
请求竞态问题统一封装
前端
loriloy8 小时前
前端资源帖
前端
源码超级联盟8 小时前
display的block和inline-block有什么区别
前端
GISer_Jing8 小时前
前端构建工具(Webpack\Vite\esbuild\Rspack)拆包能力深度解析
前端·webpack·node.js