💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[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 } ] ~~~