ES6:Set

118 阅读4分钟

一、Set是什么

Set的本质是一个对象,该对象中可以存任何数据类型的值,但是只能存一个

      const set = new Set()

      console.log(Object.prototype.toString.call(set)) // [object Set] 本质是对象

注意点:

1、Set去重采用的逻辑

  1. Set认为NaN和NaN是同一个值,尽管NaN === NaN为false,也就是说当多次插入NaN时,只会有一个NaN
      const set = new Set()
      set.add(NaN)
      set.add(NaN)
      console.log(set.size) // 1
  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、判断一个数组中是否包含另一个数组的所有元素

  1. 使用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
  1. 使用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