[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方法