首页 前端知识 一文读懂 JS 中的 Set 结构

一文读懂 JS 中的 Set 结构

2024-10-15 23:10:52 前端知识 前端哥 149 248 我要收藏

你好,我是沐爸,欢迎点赞、收藏、评论和关注。

今天聊下 Set 数据结构,看下它如何使用?和 Map 有什么区别?有哪些属性和方法?又有哪些使用场景?WeakMap 又是什么?下面直接进入正题。

一、Set 和 Map 有什么区别?

  • Set 是一个集合,类似于数组,但是成员的值都是唯一的,不能重复。主要用于快速查找、去重等场景。
  • Map 是一组键值对的集合,其中每个元素都是一个键值对。与普通的对象不同,Map 的键不仅限于字符串,也可以是任意类型(如对象或函数)。

二、WeakSet 和 Set 的区别?

WeakSet 结构与 Set 类似,也是不重复的值的集合。两者的区别在于:

  • WeakSet 的成员只能是对象和 Symbol 值,而不能是其他类型的值。
  • WeakSet 对象不计入垃圾回收机制。
  • Set 可遍历,WeakSet 不可遍历。

三、Set 实例有哪些属性和方法?

1.属性

  • constructor:构造函数,默认就是 Set 函数
  • size:返回 Set 实例的成员总数

2.方法

  • 操作方法
    • add(value) 添加某个值,返回 Set 实例本身
    • delete(value) 删除某个值,返回一个布尔值,表示删除是否成功
    • has(value) 查询该值是否是 Set 实例的成员,返回一个布尔值
    • clear() 清除所有成员,没有返回值
  • 遍历方法:
    • keys() 返回键名的遍历器
    • values() 返回键值的遍历器
    • entries() 返回键值对的遍历器
    • forEach() 使用回调函数遍历每个成员
  • 集合运算方法:
    • intersection(other) 交集
    • union(other) 并集
    • difference(other) 差集
    • symmetricDifference(other):对称差集
    • isSubsetOf(other):判断是否为子集
    • isSupersetOf(other):判断是否为超集
    • isDisjointFrom(other):判断是否不相交
// 示例1
let s1 = new Set()
s1.add(1)
s1.add(2)
s1.add(3)
s1.add(4)
s1.size // 4
s1.has(1) // true
s1.has(5) // false
s1.delete(5) // false
s1.delete(1) // true
s1.clear()

// 示例2
let s2 = new Set(['red', 'green', 'blue'])

for (let item of s2.keys()) console.log(item)
for (let item of s2.values()) console.log(item)
s2.forEach(item => console.log(item))
// 3种遍历结果相同,依次打印 red、green、blue

for (let item of s2.entries()) console.log(item)
// ['red', 'red']
// ['green', 'green']
// ['blue', 'blue']

// 示例3
let s3 = new Set(['a', 'b', 'c', 'd'])
let s4 = new Set(['c', 'd', 'e', 'f'])
let s5 = new Set(['a', 'b'])

s3.union(s4) // ['a', 'b', 'c', 'd', 'e', 'f'] 并集
s3.intersection(s4) // ['c', 'd'] 交集
s3.difference(s4) // ['a', 'b'] 差集
s4.difference(s3) // ['e', 'f'] 差集
s3.symmetricDifference(s4) // ['a', 'b', 'c', 'd', 'e', 'f'] 对称差集 = 并集 - 交集
s3.isSubsetOf(s4) // false s3不是s4的子集
s5.isSubsetOf(s3) // true s5是s3的子集
s3.isSupersetOf(s5) // true s3是s5的超集
s4.isDisjointFrom(s5) // true s4与s5不相交

四、Set 的使用场景有哪些?

1.数组去重

const set = new Set([1, 2, 3, 4, 4])
[...set] // [1,2,3,4]

2.字符串去除重复字符

[...new Set('ababbc')].join('')
// "abc"

3.集合运算

求两个数组之间的并集、交集、差集等,上面已有示例。

五、WeakSet 如何使用?

  • 成员只能是对象或 Symbol,不能是其他数据类型的值
  • 有3个方法:add、delete、has,用法同 Set
  • 没有 size 属性和 clear 方法,不支持遍历,for/forEach/keys()/values()/entries()都不能用
const ws = new WeakSet()

ws.add(1) // 报错
ws.add(Symbol()) // 不报错

const a = [[1, 2], [3, 4]]
const ws = new WeakSet(a)
// WeakSet {[1, 2], [3, 4]}

const b = [3, 4];
const ws = new WeakSet(b);
// Uncaught TypeError: Invalid value used in weak set(…)

ws.size // undefined
ws.forEach // undefined

六、WeakSet 的使用场景?

  1. 内存管理:当你需要跟踪一组对象但不希望阻止这些对象被垃圾回收时,WeakSet 是个好选择。它帮助避免内存泄漏,因为它不会阻止成员对象被自动回收。
  2. 私有成员管理:在面向对象编程中,WeakSet 可用于存储类的私有成员或状态,同时保持对内存使用的控制。
  3. 缓存失效:当缓存或映射依赖于对象存在时,使用 WeakSet 可以确保当对象被垃圾回收时,相关的缓存或映射也自动失效,减少内存浪费。
  4. DOM元素管理:在处理DOM元素时,WeakSet 可用于跟踪一组特定的元素,而无需担心因保留引用而阻止元素被垃圾回收。

七、其他知识点

1.Set() 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

// 例一
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]

// 例二
const set = new Set(document.querySelectorAll('div'));
set.size // 56

2.向 Set 加入值的时候,不会发生类型转换,类似严格相等,区别在于,Set 认为 NaN 等于 NaN。

let s = new Set()
s.add(5)
s.add('5')
s.size // 2

s.add(NaN)
s.add(NaN)
s.size // 3

3.Array.from() 方法可以将 Set 结构转为数组。

const items = new Set([1, 2, 3, 4, 2, 3]);
const array = Array.from(items); // [1, 2, 3, 4]

4.Set 具有 iterator 接口,可直接用 for…of 循环遍历。

let set = new Set(['red', 'green', 'blue']);

for (let x of set) {
  console.log(x);
}
// red
// green
// blue


好了,分享结束,谢谢点赞,下期再见。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/18997.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!