1、最简化的方法是使用ES6的set去重,set是一个集合,集合中元素不允许重复,将数组转化为集合再还原成数组就会自动去重。
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]
[...new Set(arr)]
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}] 空对象未去重
2、reduce+includes,有些会认为reduce写出来的代码可读性比较差,难以理解,但个人认为reduce的功能还是很强大的,比较灵活,有些时候还可以提高性能,将两层循环转化为一层循环,(这里去重并没有提高性能,只是一种方法供参考)
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]
arr.reduce((result,cur)=>result.includes(cur)?result:[...result,cur],[])
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}] 空对象未去重
3、使用Map,用空间换时间。reduce+includes实际上是两层循环,如果想用一层循环去重,可以使用Map映射。但这种方法就多定义了一个Map,额外占用了空间。这里的Map不能用对象替换,因为对象的key只能是字符串,用数组元素作为对象的key时,会自动转化为字符串,从而出现bug
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]
var map = new Map()
var newArr = []
arr.map((item)=>{
if(!map.has(item)){
map.set(item,item)
newArr.push(item)
}
return item
})
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}] 空对象未去重
4、使用两层map循环+splice。遇到重复元素就用splice删除。这种方法比较笨,就不再写了
5、sort+for循环。先对数组进行排序,再循环数组,比较当前元素与上一个元素是否相等,不相等则放入新数组。 由于NaN!==NaN,所以该方法去不掉NaN
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]
arr = arr.sort()
let newArr = [arr[0]]
for(let i=1;i<arr.length;i++) {
if(arr[i]!==arr[i-1]) {
newArr.push(arr[i])
}
}
// [0, 1, 15, NaN, NaN, "NaN", {}, {}, "a", false, null, "true", true, undefined] NaN和空对象未去重
6、for循环+indexOf。循环原数组,用indexOf方法比较当前元素index在新数组中是否存在,不存在则放入新数组。该方法实际也是两层循环(因为indexOf也会进行一层循环),不是很好,就不写了。
7、以上的方法对于简单类型的数组去重可行,但对于有对象的数组就不能去重了,两个空对象和两个空数组都不能去重。因此,对于复杂的数组需要递归判断元素类型。
// 判断两个变量是否相等,{}与{},[]与[]相等
function isObjectValueEqual(a, b) {
// 如果a或b不是对象,或者a或b为null,则直接对比
if(typeof a !== 'object' || typeof b !== 'object' || a===null || b===null) {
return a===b
}
//获取a和b的属性名称
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// 属性名称数组长度不相等,a和b肯定不相等
if (aProps.length != bProps.length) {
return false;
}
// 长度相等再循环属性值进行比较
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i]
var propA = a[propName]
var propB = b[propName]
if ((typeof (propA) === 'object')) {
// 属性值是对象,则递归判断
return this.isObjectValueEqual(propA, propB)
} else {
// 属性值不是对象,则根据属性值直接判断
if (propA !== propB) {
return false
}
}
}
// 循环完成,没有返回值说明所有值都相等,返回true
return true
}
// 基于方法5 进行去重
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]
arr = arr.sort()
let newArr = [arr[0]]
for(let i=1;i<arr.length;i++) {
if(!isObjectValueEqual(arr[i],arr[i-1])) {
newArr.push(arr[i])
}
}
// [0, 1, 15, NaN, NaN "NaN", {}, "a", false, null, "true", true, undefined]
// 为了去掉NaN 需要再执行方法1
[...new Set(newArr)]