你好,我是沐爸,欢迎点赞、收藏、评论和关注。
今天聊下 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 的使用场景?
- 内存管理:当你需要跟踪一组对象但不希望阻止这些对象被垃圾回收时,
WeakSet
是个好选择。它帮助避免内存泄漏,因为它不会阻止成员对象被自动回收。 - 私有成员管理:在面向对象编程中,
WeakSet
可用于存储类的私有成员或状态,同时保持对内存使用的控制。 - 缓存失效:当缓存或映射依赖于对象存在时,使用
WeakSet
可以确保当对象被垃圾回收时,相关的缓存或映射也自动失效,减少内存浪费。 - 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
好了,分享结束,谢谢点赞,下期再见。