[toc]
> 一直以来,JS只能使用数组和对象来保存多个数据,缺乏像其他语言那样拥有丰富的集合类型。因此,ES6新增了两种集合类型(set 和 map),用于在不同的场景中发挥作用。
### set集合
**set用于存放不重复的数据**
1. 如何创建set集合
```js
new Set(); //创建一个没有任何内容的set集合
new Set(iterable); //创建一个具有初始内容的set集合,内容来自于可迭代对象每一次迭代的结果
//例如:
const s1 = new Set();
const s2 = new Set([1,2,3,4,5,5,5,6]);
console.log(s1);
//输出一个空的Set集合,Set(0) {}
console.log(s2);
//s2在初始化set集合时传入了一个数组(数组为可迭代对象)做为s2的初始值。又因为set集合中存放的数据不能重复,所以自动将数组中重复的数据忽略掉,得到的结果为Set(6) {1,2,3,4,5,6}
```
除了数组外,set集合可以将任何可迭代对象做为初始化参数(包括字符串)。
>由此可见,set集合是一个将数组、字符串等可迭代对象去重的一个比较好的方法。
2. 如何对set集合进行后续操作
- add(数据): 添加一个数据到set集合末尾,如果数据已存在,则不进行任何操作
- set使用Object.is的方式判断两个数据是否相同,但是,针对+0和-0,set认为是相等
- has(数据): 判断set中是否存在对应的数据
- delete(数据):删除匹配的数据,返回是否删除成功
- clear():清空整个set集合
- size: 获取set集合中的元素数量,只读属性,无法重新赋值
3. 如何与数组进行相互转换
```js
const s = new Set([1,2,3,4,4,5,6,7,4,5,6,7]);
// set本身也是一个可迭代对象,每次迭代的结果就是每一项的值
const arr = [...s];
// 上面的代码可以简写成如下方式,直接获得一个去重后的数组
const arr = [...new Set([1,2,3,4,4,5,6,7,4,5,6,7])];
```
>字符串去重也可以先将字符串做为参数创建一个set集合,获得一个去重后的数组,然后使用join("")方法拼接成字符串。
4. 如何遍历
1). 使用for-of循环
2). 使用set中的实例方法forEach
注意:set集合中不存在下标,因此forEach中的回调的第二个参数和第一个参数是一致的,均表示set中的每一项
5. 应用案例:
利用set实现求两个数组的并集、交集、差集,结果返回一个新的数组
```js
// 定义两个数组
const arr1 = [33, 22, 55, 33, 11, 33, 5];
const arr2 = [22, 55, 77, 88, 88, 99, 99];
//求并集方法一:
console.log("并集", [...new Set(arr1.concat(arr2))]);
//求并集方法二:
console.log("并集", [...new Set([...arr1, ...arr2])]);
//求交集,定义变量cross是为了简化求差集
const cross = [...new Set(arr1)].filter(item => arr2.indexOf(item) >= 0);
console.log("交集", cross)
//求差集方法一:(判断条件,arr1有的且arr2没有的值返回,或者arr2有的且arr1没有的值返回)
console.log("差集", [...new Set([...arr1, ...arr2])].filter(item => arr1.indexOf(item) >= 0 && arr2.indexOf(item) < 0 || arr2.indexOf(item) >= 0 && arr1.indexOf(item) < 0))
//求差集方法二:(利用交集的变量,返回并集中不含交集的部分)
console.log("差集", [...new Set([...arr1, ...arr2])].filter(item => cross.indexOf(item) < 0))
```
### map集合
键值对(key value pair)数据集合的特点:键不可重复
map集合专门用于存储多个键值对数据。
在map出现之前,我们使用的是对象的方式来存储键值对,键是属性名,值是属性值。
使用对象存储有以下问题:
- 键名只能是字符串
- 获取数据的数量不方便
- 键名容易跟原型上的名称冲突
针对以上问题,ES6提供了map集合,用来弥补用对象存储数据的一些不足。
在实际开发中,可根据数据的结构来选择是使用对象存储还是map存储。
对象存储适用于属性较固定,且缺一不可的情况。例如:员工信息中的姓名,姓别,年龄等信息均需完整,缺少一项该员工信息就不完整。
map集合适用于属性数量不固定,动态增减属性不会对集合的使用造成影响。例如:一个网络请求,集合中包含的属性都是不固定的,但均可以发送请求。
1. 如何创建map
```js
new Map(); //创建一个空的map
new Map(iterable); //创建一个具有初始内容的map,初始内容来自于可迭代对象每一次迭代的结果,但是,它要求每一次迭代的结果必须是一个长度为2的数组,数组第一项表示键,数组的第二项表示值
```
2. 如何进行后续操作
- size:只读属性,获取当前map中键的数量
- set(键, 值):设置一个键值对,键和值可以是任何类型
- 如果键不存在,则添加一项
- 如果键已存在,则修改它的值
- 比较键的方式和set相同
- get(键): 根据一个键得到对应的值
- has(键):判断某个键是否存在
- delete(键):删除指定的键
- clear(): 清空map
3. 和数组互相转换
和set一样
4. 遍历
- for-of,每次迭代得到的是一个长度为2的数组
- forEach,通过回调函数遍历
- 参数1:每一项的值
- 参数2:每一项的键
- 参数3:map本身
### [扩展]WeakSet 和 WeakMap
#### WeakSet
使用该集合,可以实现和set一样的功能,不同的是:
1. **它内部存储的对象地址不会影响垃圾回收**
2. 只能添加对象
3. 不能遍历(不是可迭代的对象)、没有size属性、没有forEach方法
#### WeakMap
类似于map的集合,不同的是:
1. **它的键存储的地址不会影响垃圾回收**
2. 它的键只能是对象
3. 不能遍历(不是可迭代的对象)、没有size属性、没有forEach方法