面试官:说一说JS数组去重都有哪些方法?

179 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

前言

本篇文章主要总结JS当中常用的一些去重的方法,提供大家学习使用。如有写得不准确的地方,欢迎掘友们指出!一起学习,相互进步!

1.利用对象属性key排除重复项(不建议使用):

遍历数组,每次判断对象中是否存在该属性,不存在就存储在新数组中,并且把数组元素作为key,设置一个值,存储在对象中,最后返回新数组。

举例:

function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    var arrry= [];
     var  obj = {};
    for (var i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) {
            arrry.push(arr[i])
            obj[arr[i]] = 1
        } else {
            obj[arr[i]]++
        }
    }
    return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))

结果:两个true直接去掉了,'NaN'直接去掉了

image.png

这个方法的优点是效率较高,缺点是占用了较多空间,使用的额外空间有一个查询对象和一个新的数组。

2.利用Set类型数据无重复项([...new Set(arr)])

new 一个 Set,参数为需要去重的数组,Set 会自动删除重复的元素,再将 Set 转为数组返回。 举例:


function unique(arr) {
  return [...new Set(arr)];
}

const arr = [1, "1", {}, {}];
console.log(unique(arr)); 

结果:new Set 的方法可以区分出数据类型,但是无法去掉相同对象。(本质上是因为对象都是引用)

image.png

这个方法的优点是效率更高,代码简单,思路清晰,缺点是可能会有兼容性问题

3.filter+indexof 去重

这个方法和第一种方法类似,利用 Array 自带的 filter 方法,返回 arr.indexOf(num) 等于 index 的num。原理就是 indexOf 会返回最先找到的数字的索引,假设数组是 [1, 1],再对第二个1使用 indexOf 方法时,返回的是第一个1的索引0。

举例:

function unique(arr) {
  return arr.filter(function(item, index, arr) {
    //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
    return arr.indexOf(item, 0) === index;
  });
}
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
 console.log(unique(arr))

结果:无法去重相同对象

image.png

这个方法的优点是可以在去重的时候插入对元素的操作,可拓展性强。

4.hasOwnProperty 判断是否存在对象属性

function unique(arr) {
  var obj = {};
  return arr.filter(function(item, index, arr){
      return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  })
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
 console.log(unique(arr))

这里的typeof item + item可以输出"item数据类型 + item值"的字符串结果,然后通过hasOwnPrototype()来判断obj内是否有这个数据类型的数据(hasOwnPrototype()不会攀升原型链),如果有那么就直接返回false,根据filter()的用法,这个数据就会被过滤掉。
如果这个obj内没有这个类型的数据,那么就会通过obj[数据类型]的方式将这个类型存入obj中,并且设定值为true,同时这个数据根据filter()的用法,会保留。

结果:所有的都可去重

image.png

5.reduce +includes去重

这个方法就是利用reduce遍历和传入一个空数组作为去重后的新数组,然后内部判断新数组中是否存在当前遍历的元素,不存在就插入到新数组中。

function unique(arr){
  return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));

结果:无法去除相同对象

image.png

这种方法时间消耗多,内存空间也有额外占用。

总结

以上五个方法中,在数据低于10000条的时候没有明显的差别,高于10000条,第一种和第二种的时间消耗最少,后面三种时间消耗依次增加,由于第一种内存空间消耗比较多,且现在很多项目不再考虑低版本浏览器的兼容性问题,所以建议使用第二种去重方法,简洁方便。 还有更多一些方式可以点击JavaScript 数组去重的方法(12 种方法,史上最全)