谈谈js数组去重

谈谈js数组去重

一、前言

说到js数组去重,在一些文章中,看到某一些数组去重的方法,在判断元素是否相等时,使用的是==比较运算符。众所周知,这个运算符在比较前会先查看元素类型,当类型不一致时会做隐式类型转换。这其实是一种非常不严谨的做法。因为无法区分在做隐匿类型转换后值一样的元素,例如0、’‘、false、null、undefined等。

同时,还有可能出现一些只能黑人问号的结果,例如:

 [] == ![]; //true

二、处理方法总结

A、利用Array.prototype.indexOf()

indexOf()方法返回在该数组中第一个找到的元素位置,如果它不存在则返回-1,indexOf()使用的是严格比较,也就是===

1、第一种处理方式
 let arr1=[1,2,3,4,3,2,1,4];
 function unique(arr) {
   return arr.filter(function(item, index){
    // indexOf返回第一个索引值,
    // 如果当前索引不是第一个索引,说明是重复值
    return arr.indexOf(item) === index;
  });
}

console.log(unique(arr1));

笔记:

array.filter(function(currentValue,index,arr), thisValue)

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

注意: filter() 不会对空数组进行检测。

注意: filter() 不会改变原始数组。

2、第二种处理方式
function unique(arr) {
var ret = [];
arr.forEach(function(item){
    if(ret.indexOf(item) === -1){
        ret.push(item);
    }
   });
  return ret;
}

console.log(unique(arr1));

笔记:

array.forEach(function(currentValue, index, arr), thisValue)

forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。

注意: forEach() 对于空数组是不会执行回调函数的。

B、利用Array.prototype.includes()

Array.prototype.includes()是ES2016中新增的方法,用于判断数组中是否包含某个元素,所以上面使用indexOf()方法的第二个版本可以改写成如下版本:

笔记

注意的是,indexOf()方法和includes()对待NaN行为是完全不一样的,以下代码进行验证:

C、利用ES2015中的Map

Map是一种新的数据类型,可以把它想象成key类型没有限制的对象。此外,它的存取使用单独的get()、set()接口。

由于Map使用单独的接口来存取数据,所以不用担心key会和内置属性重名(如上文提到的__proto__)。使用Map改写一下我们的去重方法:

D、利用ES2015中的Set

除了Map以外,ES2015还引入了一种叫作Set的数据类型。

顾名思义,Set就是集合的意思,它不允许重复元素出现,这一点和数学中对集合的定义还是比较像的。

如果你重复添加同一个元素的话,Set中只会存在一个。包括NaN也是这样。于是我们想到,这么好的特性,要是能和数组互相转换,不就可以去重了吗?

E 、以前用到的双重遍历去重

双重遍历还有一个优化版本,但是原理和复杂度几乎完全一样: