乐趣区

关于前端:温泉里挣扎的set方法

始终以来,JS 只能应用数组和对象来保留多个数据,不足像其余语言那样领有丰盛的汇合类型。因而,ES6 新增了两种汇合类型 setmap,用于在不同的场景中发挥作用。因为文章篇幅的起因,明天先聊聊 set,map 将在下一篇文章再去说。

「set 汇合用于寄存不反复的数据」

0、如何创立 set 汇合

new Set();// 创立一个没有任何内容的 set 汇合
new Set(iterable);// 创立一个具备初始内容的 set 汇合,内容来自于可迭代对象每一次迭代的后果

例:创立没有内容的 set 汇合

const result = new Set();
 console.log(result);

执行后果:

例:创立一个可迭代对象的汇合

const result = new Set([1,3,3,4,5,5,6]);
 console.log(result);

执行后果:

在文章结尾咱们就提到 set 汇合用于寄存不反复的数据, 所以最初输入后果就是不反复的数组,这也是一种非常简单的数组去重的形式。当然 Set(数据) 的参数不肯定是数组,只有是可迭代对象都能够,甚至能够是 字符串, 如下:

const result = new Set('abbccdde');
 console.log(result);

执行后果:

如果是字符串,它会先转换为 String 对象,String 对象其实是可迭代对象, 从执行后果来看 Set 汇合不仅能够用于 数组去重 ,也能够用于 字符串去重

1、如何对 set 汇合进行后续操作

「1、add(数据):增加一个数据到 set 汇合开端, 如果数据已存在,则不进行任何操作」

例:应用 add 增加数据

 const result = new Set();
        result.add(1);
        result.add(2);
        result.add(3);
        result.add(1);// 有效代码,Set 外部会认为这条数据跟后面的数据反复
        result.add(2);// 有效代码,Set 外部会认为这条数据跟后面的数据反复
        console.log(result);

执行后果:

这外面有个细节大家要 留神!下:set 外面它是怎么判断两个数据是否雷同呢?set 应用 Object.is 的形式判断两个数据是否雷同,而不是用=== 严格相等, 然而,针对 + 0 和 -0,set 认为它们是相等的,什么意思呢?其实是这样:

Object.is(+0,-0);// 返回 false
+0 === -0;// 返回 true

原本 set 是应用 Object.is 形式来判断数据是否相等,但 set 独自针对这块又把 + 0 和 - 0 看成相等的。代码测试:

 const result = new Set();
        result.add(1);
        result.add(2);
        result.add(3);
        result.add(1);// 有效代码,Set 外部会认为这条数据跟后面的数据反复
        result.add(2);// 有效代码,Set 外部会认为这条数据跟后面的数据反复
        result.add(+0);
        result.add(-0);// 因而这段代码是有效的
        console.log(result);

执行后果:

本不应该呈现这种状况的,之所以呈现这个问题,纯正是设计的问题,设计者预计是没方法开脱的,他不应该这样去设计,一个语言设计上它要对立。ES 的设计不可能是一个人实现的,是很多人一起设计开发的,难免会造成不对立的状况。

还有一点就是如果判断的数据是对象是否相等,那么就要判断它的地址是否相等。

「2、has(数据):判断 set 中是否存在对应的数据」

因为 set 汇合中曾经应用 add 增加好数据,那么我间接应用 has 办法

执行后果:

「3、delete(数据):删除匹配的数据,返回是否删除胜利」

执行后果:

如果删除存在的数据就会返回 true,如果是删除不存在的数据,则返回 false

「4、clear(): 没有参数,清空整个 set 汇合」

执行后果:

2、如何与数组进行转换

例:数组转换成 set 汇合

const result = new Set(要转换的数组)

例:set 汇合转换为数组

const arr = [...result];

接下来咱们看一个小例子:要求就是把一个数组去重之后失去一个新的数组。

例:数组去重失去新的数组

var arr = [1,1,33,44,21,23,56,34,56,56,77,77];
const result =[...new Set(arr)];
console.log(result);

执行后果:

以上就是非常简单地数组去重办法

顺便写下字符串去重

例:字符串去重

var str = 'asndjfnajsknfdqwpsfdnsifnasnfdijsf';
const result =[...new Set(str)].join(" ");
console.log(result);

执行后果:

3、如何遍历

方才咱们曾经说了,set 自身是可迭代对象,因而能够用 for of 循环进行遍历。

  • 应用 forof 进行遍历
const result = new Set([1,1,33,44,21,23,56,34,56,56,77,77]);
 for (const item of result) {console.log(item);
}

执行后果:

  • 应用 set 中实例办法forEach
 const result = new Set([1,1,33,44,21,23,56,34,56,56,77,77]);
 result.forEach(item => {console.log(item);
})

执行后果:

应用 forEach 遍历咱们要留神,在数组中进行遍历的时候,forEach 是有三个参数的 forEach(item,index,that), 第一个参数是每一项的值,第二个参数是下标,第三个参数是数组自身。然而在 set 外面是有差异的,咱们加上三个参数试试:

const result = new Set([1,1,33,44,21,23,56,34,56,56,77,77]);
 result.forEach((item,index,that) => {console.log(item,index,that);
  })

执行后果:

咱们能够发现第一个参数和第三个参数没有问题,因为在数组中第一个参数也是每一项的值,第三个参数是数组自身,而第二个参数却不是下标,那为什么不是下标呢?

留神: set 汇合中不存在下标,因为下标是数组特有的货色,不要认为是汇合特有的货色,比方,对象也是汇合,外面能够存多个数据,对象就没有下标。因而在 set 汇合中是不可能获取下标的,那自然而然不可能用一般 for 循环去循环它的下标,如果说肯定要用下标的话,能够先把 set 汇合转换为数组再应用它的下标。因为 set 汇合中不存在下标,那么第二个参数就不是下标了。

但 forEach 又要放弃格局统一性,之所以要放弃格局对立是因为咱们有可能会写一些通用的回调函数既适宜数组调用,又适宜 set 汇合,为了保障通用性,因而 set 汇合中的 forEach 依然会保留第二个参数,只不过第二个参数跟第一个参数是一样的,都示意汇合中的每一项。

「set 汇合中不存在下标,因而 forEach 中的回调的第二个参数和第一个参数是统一的,均示意 set 中的每一项。」

4、set 汇合的利用

求两个数组的并集、交加、差集(不能呈现反复项),失去的后果是一个新数组

例:求并集

const arr1 = [22,33,55,33,11,5,6];
const arr2 = [22,55,77,88,88,99];
// 办法一:const result = [...new Set(arr1.concat(arr2))];
console.log("并集",result);
// 办法二:const result = [...new Set([...arr1,...arr2])];
console.log("并集:",result);

执行后果:

例:求交加

const arr1 = [22,33,55,33,11,5,6];
const arr2 = [22,55,77,5,88,99];
// 办法一:const s1 = new Set(arr1);
const s2 = new Set(arr2);
const result = [...s1].filter(item => s2.has(item));
console.log("交加:",result);
// 办法二
const s = new Set(arr1);
const result = [...s].filter(item => arr2.indexOf(item) >=0 )
console.log("交加:",result);

执行后果:

例:求差集

const arr1 = [22,33,55,33,11,5,6];
const arr2 = [22,55,77,5,88,99];
// 办法一
const s1 = new Set(arr1);
const s2 = new Set(arr2);
const result = new Set([...s1,...s2].filter(item => !s2.has(item) || !s1.has(item)));
console.log("差集:",result);
// 办法二
const s1 = new Set(arr1);
const s2 = new Set(arr2);
const result = [...s1,...s2].filter(item =>arr1.indexOf(item) >=0 && arr2.indexOf(item) <0 || arr2.indexOf(item) >=0 && arr1.indexOf(item)<0)
console.log("差集:",result);

执行后果:

5、手写 set 办法

咱们手写的 set 办法跟浏览器提供的 set 比照的话必定是不一样的,因为浏览器在实现 ES 规范的时候,它是能够调用底层资源的,比如说能够间接操作内存,它的效率要比咱们手写的 set 办法效率高些。手写源码能够拓展咱们的思维,仅此而已。

1、新建 mySet.js 文件

class MySet {
    // 构造函数外面参数可传可不传,给参数一个默认值就能够了
    constructor(iterable = []) {
        // 验证传入的参数是否是可迭代对象, 可迭代的对象类型肯定是个对象
        if (typeof iterable[Symbol.iterator] !== 'function') {throw new TypeError(`${typeof iterator} ${iterator} is not iterable (cannot read property Symbol(Symbol.iterator))`)
        }
        this._datas = []; // 因为不能操作底层内存,所以申明一个数组用于存放数据
        // 上面验证通过,迭代每一个可迭代的对象,把每一项放到  MySet 外面去
        for (const item of iterator) {
            // 每迭代一次,把 item 加到 MySet 外面去,问题转为封装 add 办法
            this.add(item);
        }
    }
    // 给 MySet 增加数据
    add(data) {
        // 这里加数据的时候有个前提条件,就是反复的数据只放一次, 问题转为封装 has 办法
        if (!this.has(data)) {this._datas.push(data);
        }
    }
    // 判断 MySet 中是否存在对应的数据
    has(data) {
        // 这里判断是否有雷同的值,问题转为封装 isEqual 办法
        for (const item of this._datas) {if (this.isEqual(data, item)) {return true;}
        }
        return false;
    }
    // 删除 MySet 中对应的数据
    delete(data) {for (let i = 0; i < this._datas.length; i++) {const element = this._datas[i];
            if (this.isEqual(element, data)) {
                // 删除
                this._datas.splice(i, 1);
                return true;
            }
        }
        return false;
    }
    // 清空整个数组
    clear() {this._datas.length = 0;}
    *[Symbol.iterator]() {for (const item of this._datas) {yield item;}
    }
    forEach(callback) {for (const item of this._datas) {callback(item, item, this);
        }
    }
    /**
     * 判断两个数据是否相等
     * @param {*} data1 
     * @param {*} data2 
     */
    isEqual(data1, data2) {
        // 如果 data1 和 data2 都等于 0,那么咱们认为它们相等
        if (data1 === 0 && data2 === 0) {return true;}
        return Object.is(data1, data2);
    }
}

代码测试:求差集

`<script src=”js/mySet.js”></script>
    <script > const arr1 = [22,33,55,33,11,5,6];
        const arr2 = [22,55,77,5,88,99];
        const s1 = new MySet(arr1);
        const s2 = new MySet(arr2);
        const result = new MySet([…s1,…s2].filter(item => !s2.has(item) || !s1.has(item)));
        console.log(“ 差集:”,result); </script>`

执行后果

代码测试:add、has、delete、clear

<script src="js/mySet.js"></script>
<script > const result = new MySet();
       result.add(1);
       result.add(2);
       result.add(3);
       result.add(4);
       console.log(result);</script>

以上就是我的分享,心愿能帮到大家!欢送大佬一起探讨 ……

退出移动版