[TOC]
>[success] # Set集合
~~~
'ES6'的'Set類型'是一種'有序列表、無重復的列表',通過'Set集合'可以快速訪問其中的數據。
~~~
<br/>
>[success] ## 創建Set集合并添加元素
1. **添加元素**
~~~
let set = new Set() // 創建Set集合
set.add(5); // 添加元素
set.add("5");
console.log(set.size); // 2 打印set元素個數
~~~
2. **值不同保持獨立**
在**Set集合**中,不會對所存值進行強制的**類型轉換**,**數字5**和**字符串5**是兩個**獨立元素**,用[Object.is()](http://www.hmoore.net/wangjiachong/javascript/1364568)可以進行判斷兩個值是否一致,如果向**Set集合**中**添加**多個對象,則他們之間**保持獨立**:
~~~
let set = new Set(),
key1 = {},
key2 = {};
set.add(key1); // 添加一個對象
set.add(key2); // 添加一個對象
console.log(set.size) // 2
~~~
由于**key1**和**key2**不會被轉換成**字符串**,因為它們在**Set集合**中是兩個獨立的元素,如果被轉換,則兩者都是 **[object object]** 。
3. **值相同,忽略后續相同值**
如果多次調用**add()** 方法并傳入相同的值作為參數,那么后續的調用實際上會被忽略:
~~~
let set = new Set();
set.add(5)
set.add('5')
set.add(5) // 重復 - 本次調用直接被忽略
console.log(set.size) // 2
~~~
4. **用數組初始化Set集合**
~~~
let arr = [1, 2, 3, 4, 5, 5, 5, 5]; // 創建一個數組
let set = new Set(arr); // 用數組初始化Set集合
console.log(set.size) // 5
~~~
在上面的代碼中,我用一個包含**重復元素**的**數組**來初始化**Set集合**,數組中有**4個5**,而在生成的集合中只有**一個5**,**自動去重**的功能適合對**已有數據**和**JSON**結構數據轉換成**Set集合**比較好。實際上**Set構造函數**可以接受**所有可迭代對象**作為參數,**數組**、**Set集合**、**Map集合**都是可迭代的,因而都可以作為**Set構造函數**的**參數**使用;**構造函數**通過**迭代器**從參數中提取值,后期會學到**迭代器**。
>[success] ## 檢測Set集合中某個元素是否存在
~~~
let arr = [1, 2, 3, 4, 5, 5, 5, 5]; // 創建一個數組
let set = new Set(arr); // 用數組初始化Set集合
console.log(set.has(5)) // true
~~~
<br/>
>[success] ## 刪除元素
調用**delete()** 方法可以**移除Set集合中的某一個元素**,調用 **clear()** 方法會**移除集合中的所有元素**。
1. delete()
~~~
let set = new Set([ 5 ]); // 創建一個Set集合
set.delete(5); // 刪除元素
console.log(set.has(5)) // false
~~~
2. clear()
~~~
let set = new Set([ 5, 6 ]); // 創建一個Set集合
set.clear(); // 刪除所有元素
console.log(set.size) // 0
~~~
<br/>
>[success] ## Set集合的forEach()方法
1. 基礎寫法
~~~
let set = new Set([1,2,3])
set.forEach((a,b,c) => {
console.log(a,b,c)
})
// 打印結果
// 1 1 Set { 1, 2, 3 }
// 2 2 Set { 1, 2, 3 }
// 3 3 Set { 1, 2, 3 }
~~~
2. **數組forEach**、Set集合**forEach**、**Map集合forEach**的不同之處
以上所說的**3種forEach**都有2個參數一個**callback**,一個**this**(基本上現在用不到了因為用**箭頭函數**可以解決**this指向**問題)參數,不同之處是**數組的forEach的callback的回調參數是值和索引值**,**Set集合和Map集合的forEach的callback的回調參數是值和鍵名**
~~~
// 1. 數組循環
let arr = [1,2,3]
arr.forEach((a,b,c) => { // 參數1:值,參數2:索引值,參數3:數據源
console.log(c == arr) // true
console.log(a,b,c,'數組')
// 打印結果:
// 1 0 [ 1, 2, 3 ] '數組'
// 2 1 [ 1, 2, 3 ] '數組'
// 3 2 [ 1, 2, 3 ] '數組'
})
// 2. Set集合
let setArr = new Set([1,2,3])
setArr.forEach((a,b,c) => { // 參數1:值,參數2:鍵名,參數3:數據源
console.log(c == setArr) // true
console.log(a,b,c,'Set集合')
// 打印結果:
// 1 1 Set { 1, 2, 3 } 'Set集合'
// 2 2 Set { 1, 2, 3 } 'Set集合'
// 3 3 Set { 1, 2, 3 } 'Set集合'
})
// 3. map集合
//
~~~
3. **forEach中callback的this指向問題**
**Set集合**的**forEach**方法也具備跟跟**數組集合**的**forEach**方法同樣的解決**this指向**的參數,只需要在**callback參數**后面緊接著寫一個**this**即可解決該問題,或者寫成**箭頭函數**、**bind()** 等方法都可以。
~~~
let set = new Set([1, 2, 3]) // 創建一個Set集合并且初始化賦值
let obj = {
fun(val) {
console.log(JSON.stringify(val))
},
fun2() {
set.forEach(function (item) {
this.fun(item)
}, this) // forEach的第二個參數寫成this可以改變執向
}
}
obj.fun2()
~~~
<br>
>[success] ### Set集合的forEach時注意事項
~~~
雖然說'Set集合'的'forEach'也可以像'數組'的'forEach'一樣'操作每一個元素',但是你
'不能像訪問數組元素那樣直接通過索引訪問集合中的元素'。如有需要先將'Set集合轉換成數組'
~~~
<br>
>[success] ## Set集合和數組互相轉換和數據去重
1. 將**數組轉換成Set集合**只需要給**Set構造函數傳入數組**即可。
~~~
let set = new Set([1, 2, 3]) // 創建一個Set集合
console.log(set.size) // 3
~~~
2. 將**Set集合轉換成數組**只需要用**擴展運算符(...)** 即可
~~~
let set = new Set([1, 2, 3, 3]) // 創建一個Set集合
let arr = [...set] // set集合轉換成數組
console.log(arr) // [ 1, 2, 3 ]
~~~
在上面例子中用一個**含有重復元素的數組**來初始化Set集合,集合會**自動移除重復元素**,然后再用**擴展運算符**將元素放入到這個新數組中。
**Set集合**依然保留創建時接受的元素(1、2、3、3),新數組中保存中這些元素的副本,**自動移除重復元素不會改變數據源**。
3. **用Set集合過濾數組重復元素**
~~~
function eliminateDuplicates(items) { // 消除重復
return [...new Set(items)]
}
let numbers = [1, 2, 3, 3, 3, 4, 5] // 定義一個重復元素的數組
console.log(eliminateDuplicates(numbers)) // [ 1, 2, 3, 4, 5 ]
簡化后:
let eliminateDuplicates = items => [...new Set(items)]
console.log(eliminateDuplicates(numbers)) // [ 1, 2, 3, 4, 5 ]
~~~
這個方法只能過濾重復的**普通數組(不包括多維數組)**,不可以過濾**對象數組**。
4. **對象數組去重**
4.1 循環儲存值進行對比的思路進行**去重**
~~~
// 重復元素的對象數組
let dataArr = [
{
num: 0
},
{
num: 0
},
{
num: 0
}
]
/**
* 【數組對象】根據對象屬性值去重數據
* @param { Array } arr 對象數組
* @param { String } name 去重條件的屬性名
*/
function eliminateDuplicates(arr, name){
let numbersArr = []
let data = []
arr.forEach(i => {
if(!numbersArr.includes(i[name])){
numbersArr.push(i[name])
data.push(i)
}
})
return data
}
console.log(eliminateDuplicates(dataArr,'num')) // [ { num: 0 } ]
~~~
4.2 使用**數組**提供的**reduce**方法**去重**
reduce(callback, initialValue)
| 參數1 | 參數2 |
| --- | --- |
| **callback**(accumulator, currentValue, index, array) | initialValue |
| **accumulator**:累計器累計回調的返回值; 它是上一次調用回調時返回的累積值,或**initialValue**(見參數2)。 | 作為第一次調用 **callback** 函數時的**第一個參數的值**。 **如果沒有提供初始值,則將使用數組中的第一個元素。 在沒有初始值的空數組上調用 reduce 將報錯**。 |
| **currentValue**:數組循環的**item** | |
| **index**:數組循環時的**index**索引值 | |
| **array**:調用 **reduce()** 的數組 | |
~~~
/**
* 【數組對象】根據對象屬性值去重數據
* @param { Array } arr 對象數組
* @param { String } name 去重條件的屬性名
*/
function eliminateDuplicates(arr, name){
let hash = {};
return arr.reduce(function (count, item) {
hash[item[name]] ? '' : hash[item[name]] = true && count.push(item);
return count
}, [])
}
console.log(eliminateDuplicates(dataArr,'num')) // [ { num: 0 } ]
~~~
4.3 使用**ES6**的**map集合去重**
~~~
/**
* 【數組對象】根據對象屬性值去重數據
* @param { Array } arr 對象數組
* @param { String } name 去重條件的屬性名
*/
function eliminateDuplicates(arr, name) {
let map = new Map()
arr.forEach((item, index) => {
if (!map.has(item[name])) {
map.set(item[name], item)
}
})
return [...map.values()]
}
console.log(eliminateDuplicates(dataArr, 'num')) // [ { num: 0 } ]
~~~
- Javascript基礎篇
- Array數組
- 數組插入值
- filter()
- forEach()
- push()
- pop()
- unshift()
- shift()
- valueOf()
- 面向對象思想
- Javascript 面向對象編程(一):封裝
- Javascript面向對象編程(二):構造函數的繼承
- Javascript面向對象編程(三):非構造函數的繼承
- 解構
- 數組的解構賦值
- 對象的解構賦值
- 函數參數解構
- 字符串的解構賦值
- 數值和布爾值的解構賦值
- 圓括號問題
- 字符串.
- split()
- charAt()
- charCodeAt()
- concat()
- indexOf()
- lastIndexOf()
- match()
- replace()
- includes()
- 初識遞歸
- 渲染ul-li樹形結構
- 異步函數解決方案
- 1. callback回調函數
- 2. ES6 - Promise
- JavaScript高級程序設計(書)
- 在html中使用JavaScript
- script標簽的位置
- 延遲腳本
- 異步腳本
- <noscript>元素
- 基本概念
- 嚴格模式
- 變量詳解
- 數據類型
- typeof操作符
- undefined類型
- Null類型
- Boolean類型
- Number類型
- 深入了解ES6(書)
- var 、let 、 const
- 字符串與正則表達式
- 字符串
- 正則表達式
- 函數
- 函數形參默認值
- 使用不具名參數
- 函數構造器的增強能力
- 擴展運算符
- name屬性
- 明確函數的多重用途
- 塊級函數
- 箭頭函數
- 尾調用優化
- 擴展的對象功能
- 對象類別
- 對象字面量語法的擴展
- ES6對象新增方法
- 重復的對象屬性
- 自有屬性的枚舉順序
- 更強大的原型
- 解構:更方便的數據訪問
- 為什么要用解構?
- 對象解構
- 數組解構
- 混合解構
- 參數解構
- Symbol與Symbol屬性
- 創建Symbol
- Symbol的使用方法
- Symbol全局私有屬性
- Symbol與類型強制轉換
- Symbol屬性檢索
- Symbol的一些構造方法
- Set集合與Map集合
- Set集合
- Weak Set集合(弱引用Set集合)
- Map集合
- JS標準內置對象
- Object 構造函數及屬性
- Object 構造方法
- Symbol 內建對象類的函數及屬性
- Set 構造函數及屬性
- Weak Set 構造函數及屬性
- JS雜項
- 類數組對象
- Class類的理解和使用