一、Set是什么
Set的本质是一个对象,该对象中可以存任何数据类型的值,但是只能存一个
const set = new Set()
console.log(Object.prototype.toString.call(set)) // [object Set] 本质是对象
注意点:
1、Set去重采用的逻辑
- Set认为NaN和NaN是同一个值,尽管NaN === NaN为false,也就是说当多次插入NaN时,只会有一个NaN
const set = new Set()
set.add(NaN)
set.add(NaN)
console.log(set.size) // 1
- Set采用
零值相等算法进行比较,Set曾经使用同值相等(+0和-0是不同的两个值,符合Object.is)
const set = new Set()
set.add(+0)
set.add(-0)
set.add(0)
console.log(set.size) // 1
推荐:Object.is()
2、Set内部实现了iterator(迭代器)接口,所以可以使用扩展运算符和for...of进行遍历,遍历的顺序为插入的顺序
const set = new Set()
set.add(1)
set.add('2')
set.add(['a'])
set.add({ name: 'xx' })
set.add(undefined)
set.add(null)
set.add(function () {})
set.add(true)
for (const item of set) {
console.log(item)
}
const arr = [...set]
console.log(arr) // [1, '2', Array(1), {…}, undefined, null, ƒ, true]
二、如何创建Set
通过new调用Set构造函数,传入一个数组作为Set的初始值,通过add方法可以追加值
const set = new Set([1, 2, 3])
set.add(4)
console.log(set) // Set(4) {1, 2, 3, 4}
三、Set实例的属性和方法
1、add:追加值
const set = new Set([1, 2, 3])
set.add(4)
console.log(set) // Set(4) {1, 2, 3, 4}
注意不要这样写:
const set = new Set()
set['a'] = 'a'
console.log(set) // Set(0) {a: 'a', size: 0}
console.log(set.has('a')) // false
这样写不会报错,但是没有实质意义
2、delete:删除某个值
const set = new Set([1, 2, 3])
set.delete(2)
console.log(set) // Set(2) {1, 3}
3、has:判断是否包含某个值
const set = new Set([1, 2, 3])
console.log(set.has(2)) // true
set.delete(2)
console.log(set.has(2)) // false
4、clear:清空Set对象内的所有元素
const set = new Set([1, 2, 3])
set.clear()
console.log(set) // Set(0) {size: 0}
5、forEach:按插入顺序遍历Set
const set = new Set([1, 2, 3])
set.forEach((item) => {
console.log(item) // 1 2 3
})
6、keys/values/entries:返回迭代器对象,键与值是相等的
const set = new Set([1, 2, 3])
const keys = set.keys()
const values = set.values()
const entries = set.entries()
console.log(keys) // SetIterator {1, 2, 3}
console.log(values) // SetIterator {1, 2, 3}
console.log(entries) // SetIterator {1 => 1, 2 => 2, 3 => 3}
7、size:获取Set的长度
四、Set和数组的相互转换
1、数组转为Set:使用Set构造函数将一个数组转为Set对象
const nums = [1, 2, 3]
const set = new Set(nums)
2、Set对象转为数组
可以通过扩展运算符或Array.from
const set = new Set([1, 2, 3])
const arr = [...set]
const arr1 = Array.from(set)
console.log(arr) // [1, 2, 3]
console.log(arr1) // [1, 2, 3]
五、Set的实际用途:集合操作
1、数组去重
const arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, true, NaN, NaN, +0, -0]
const newArr = [...new Set(arr)] // 要注意:多个NaN会剩下一个,+0和-0也会被认为是同一个值
console.log(newArr) // [1, 2, 3, 4, 5, true, NaN, 0]
注意:这种去重只能是简单数据类型的去重,引用数据类型无法做到去重,因为2个对象的值都是{},但是它们来自不同的指针
const arr = [{}, {}, 1, 1]
console.log([...new Set(arr)]) // [{}, {}, 1]
如果需要对数组中的对象去重,可以使用lodash的uniqBy方法
2、求交集
const arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, true]
const arr1 = [1, 2, 3, 1, 2, 3, false]
const res = [...new Set(arr)].filter((n) => new Set(arr1).has(n)) // 交集
console.log(res) // [1, 2, 3]
封装函数:
const intersection = (setA, setB) => {
setA = new Set(setA)
const _intersection = new Set()
for (const elem of setB) if (setA.has(elem)) _intersection.add(elem)
return [..._intersection]
}
console.log(intersection(arr, arr1)) // [1, 2, 3]
3、求差集
const arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, true]
const arr1 = [1, 2, 3, 1, 2, 3, false]
const res = [...new Set(arr)].filter((n) => !new Set(arr1).has(n)) // 差集:arr在前arr1在后意思是arr中有的arr1中没有
console.log(res) // [4, 5, true]
封装函数:
const difference = (setA, setB) => {
const _difference = new Set(setA)
for (const elem of setB) _difference.delete(elem)
return [..._difference]
}
console.log(difference(arr, arr1)) // [4, 5, true]
4、合并去重
const arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, true]
const arr1 = [1, 2, 3, 1, 2, 3, false]
const res = [...new Set([...arr, ...arr1])]
console.log(res) // [1, 2, 3, 4, 5, true, false]
利用Set的add方法封装函数求并集:
const union = (setA, setB) => {
const _union = new Set(setA)
for (const elem of setB) _union.add(elem)
return Array.from(_union)
}
console.log(union(arr, arr1)) // [1, 2, 3, 4, 5, true, false]
5、判断一个数组中是否包含另一个数组的所有元素
- 使用every和includes判断
const a = [1, 2, 3, 4, 5, 6, 7, 8]
const b = [5, 5, 1, 2]
const c = [3, 9]
// 判断arr1是否包含arr2
const isInclude = (arr1, arr2) => arr2.every((val) => arr1.includes(val))
console.log(isInclude(a, b)) // true
console.log(isInclude(a, c)) // false
- 使用Set
const isSuperset = (set, subset) => {
set = new Set(set)
for (const elem of subset) if (!set.has(elem)) return false
return true
}
console.log(isSuperset(a, b)) // true
console.log(isSuperset(a, c)) // false