[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()](https://www.kancloud.cn/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类的理解和使用