定义

一种 新的数据结构

  1. let s = new Set()
  2. console.log('s', s);
  3. let s1 = new Set([1, 2, 3]);
  4. console.log('s1', s1);

image.png

特点:每个元素都是唯一的

如果出现重复的元素,会自动的过滤掉

let s2 = new Set([1, 1, 1, 1, 222, 222]);
console.log('s2', s2);

image.png

常用方法

add() 新增数据

let s3 = new Set();
s3.add('imooc');
s3.add('es6')
console.log('s3', s3);

image.png

Set 支持方法的链式调用

let s4 = new Set();
s4.add('simpleSky12').add('潜龙勿用')
console.log('s4', s4);

image.png

delete() 删除 set集合中的 数据

let s5 = new Set([1, 21, 13, 24, 35]);
s5.delete(21);
console.log('s5删除后', s5);

image.png
这里删除方法中 需要传入的参数,为 数组内 元素的 value,而不是 相应的 下标,
上面的代码可以看出我们将set集合中第二个元素 21 删除了

clear() 清空 Set 集合

let s6 = new Set([1, 21, 13, 24, 35]);
s6.clear();
console.log('s6', s6);

image.png

has() 是否包含某元素

这个方法会返回一个 boolean 值

let s7 = new Set(['simpleSky12', '潜龙勿用']);
const flag = s7.has('潜龙勿用');
console.log('flag', flag); // true

size 获取集合的长度

let s8 = new Set([1, 21, 13, 24, 35]);
const size = s8.size
console.log('size', size); // 5

size 是 集合的 一个属性,并不是 集合的 方法,这一点需要注意

遍历

forEach()

let s9 = new Set([1, 21, 13, 'imooc', 'es6']);

s9.forEach(item => {
  console.log(item);
});

image.png

for of

let s9 = new Set([1, 21, 13, 'imooc', 'es6']);

for (let item of s9) {
  console.log('item', item);
}

for (let item of s9.keys()) {
  console.log(item)
}

for (let item of s9.values()) {
  console.log(item);
}

for (let item of s9.entries()) {
  console.log(item);
}

image.png
看打印结果我们可以知道, set 集合的 key 和value 是相同的

应用场景

单个数组去重

let arr = [1, 2, 2, 2, 33, 33, 1];
let s10 = new Set(arr);
console.log('s10', s10);

image.png

两个数组的合并去重

let arr1 = [1, 2, 3, 4];
let arr2 = [2, 3, 4, 5, 6];
let set = new Set([...arr1, ...arr2]);
console.log('set', set);

let arrRes = [...set];
console.log('arrRes', arrRes);

let arrRes2 = Array.from(set);
console.log('arrRes2', arrRes2);

image.png
这里 第一步是将 连个数组合并去重 成为一个新的 set 对象,但是我们想要得到的是一个 数组类型的数据,所以需要 将 set 转化成 数组arrar,
两种方法,
一个是 用 扩展运算符 + 解构赋值的方式,
一种是 用 Array.from() 将 伪数组 对象转化成,数组对象

交集去重

两个数组重复的元素的集合

利用 数组的 filter() 方法 和 set 的 has() 方法,进行去重筛选
filter 会 遍历数组中 符合条件的 元素,并且将这些元素 返回成一个新的数组

// 交集
let s2 = new Set(arr2)

const resultArr = arr1.filter(item => {
  console.log(s2.has(item))
  return s2.has(item)
});
console.log('resultArr', resultArr)

const resultSet = new Set(resultArr)
console.log('result', resultSet)

const result = Array.from(resultSet)
console.log(result)

image.png

差集去重

两个 数组,不重复的 元素的 集合
差集就是 交集的 对立面, 我们主要去除 两个数组的 交集,就可以得到他们的差集
这里主要使用 !Set.has() 来取反,拿到 两个数组中不重合的 元素

let arr1 = [1, 1,2, 2, 3, 3, 4, 4];
let arr2 = [2, 3, 4, 5, 6];

const s1 = new Set(arr1);
const s2 = new Set(arr2);

let resultSet1 = new Set(arr1.filter(item => !s2.has(item)))
let resultSet2 = new Set(arr2.filter(item => !s1.has(item)))

console.log('resultSet1',resultSet1)
console.log('resultSet2',resultSet2)

let result = [...resultSet1, ...resultSet2]
console.log('result', result)

image.png

WeakSet

与 set 的 大部分 api 方法一致,主要的区别就是 WeakSet 只能存放 对象,不能像 Set 可以 存放 基本类型的数据,字符串或者数值这样的

let ws = new WeakSet()

const obj1 = {
  name: 'imooc'
}
const obj2 = {
  age: 5
}

ws.add(obj1)
ws.add(obj2)
console.log('add-ws', ws)

ws.delete({
  name: 'imooc'
})
console.log('delete-ws', ws)

image.png

WeakSet 的 添加和删除 与 Set 保持一致, 后面 delete() 删除方法没有生效的原因是 对象的 内容虽然一样,但是 两个对象 在堆内存中的 内存地址是不一样的,他们不是同一个对象,所以没有删除成功

ws.delete(obj1)
console.log('delete-ws', ws)

image.png
只要我们将 obj1 传入,就可以删除成功了

WeakSet 是一种 弱引用, 不支持 forEach()

垃圾回收机制 GC

如果一个变量 一直处于一个 被引用状态,那么垃圾回收机制就无法 对这个变量生效,就无法 回收这个变量所 占用的 内存,这样的 变量如果越来越多,就会造成 内存泄露。
WeakSet 是一种 弱引用,不会算在 垃圾回收机制中, 也就不会出现 内存泄露的问题。
WeakSet 可以用来 存放 一些临时的数据,如果 WeakSet 引用的 对象 被销毁 ,那么 WeakSet 中存储的 对象也会消失

let ws = new WeakSet()

const obj1 = {
  name: 'imooc'
}
const obj2 = {
  age: 5
}

ws.add(obj1)
ws.add(obj2)
console.log('add-ws', ws)

ws.delete(obj1)
console.log('delete-ws', ws)

image.png
我们将 WeakSet 中的 数据结构展开后发现,我们 后面使用的 delete 方法,是会影响到 上面 两个 add 方法的 打印结果

WeakSet 与 Set 之间的 区别

  1. WeakSet 只可以 存储对象
  2. Set 可以被循环遍历,而 WeakSet 不可以
  3. WeakSet 是一种 弱引用,不会被 垃圾回收机制所考虑。WeakSet 引用的对象 被销毁 ,那么 对应的 引用关系也会消失