开启掘金成长之旅!这是我参与「掘金日新计划 · 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'直接去掉了
这个方法的优点是效率较高,缺点是占用了较多空间,使用的额外空间有一个查询对象和一个新的数组。
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 的方法可以区分出数据类型,但是无法去掉相同对象。(本质上是因为对象都是引用)
这个方法的优点是效率更高,代码简单,思路清晰,缺点是可能会有兼容性问题
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))
结果:无法去重相同对象
这个方法的优点是可以在去重的时候插入对元素的操作,可拓展性强。
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()的用法,会保留。
结果:所有的都可去重
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));
结果:无法去除相同对象
这种方法时间消耗多,内存空间也有额外占用。
总结
以上五个方法中,在数据低于10000条的时候没有明显的差别,高于10000条,第一种和第二种的时间消耗最少,后面三种时间消耗依次增加,由于第一种内存空间消耗比较多,且现在很多项目不再考虑低版本浏览器的兼容性问题,所以建议使用第二种去重方法,简洁方便。 还有更多一些方式可以点击JavaScript 数组去重的方法(12 种方法,史上最全)