实现数组去重的方法有很多, 如果不考虑兼容性, 可以直接用ES6的 Set 和 展开运算符… 实现。但如果遇到了需要根据实际情况特殊处理的, 就需要用到比较原生的方式去灵活实现。
/**
* 初始数据arr
*/
const arr = [
{a:1,b:2},
{b:2,a:1},
{a:1,b:2,c:{a:1,b:2}},
{a:1,b:2,c:{b:2,a:1}},
]
先来看一下用Set()
去重:
/**
* Set方法去重
*/
const newArr = [...new Set(arr)];
console.log(newArr);
//对象数组去重
//对象均为 Plain Object
//只要对象的所有属性值相同, 则表示相同对象
/** 输出
[
{ a: 1, b: 2 },
{ b: 2, a: 1 },
{ a: 1, b: 2, c: { a: 1, b: 2 } },
{ a: 1, b: 2, c: { b: 2, a: 1 } }
]
显然, 这里用set无法实现对象数组去重
*/
再来看一下比较原生的数组去重方法:
/**
* 最原始的去重方法
*/
const newArr02 = [...arr];
for(let i=0;i<newArr02.length;i++){
for(let j=i+1;j<newArr02.length;j++){
if(newArr02[i]===newArr02[j]){ // ===严格对等, 和set的原理一致
newArr02.splice(j,1);
j--;
}
}
}
console.log(newArr02);
/** 输出
[
{ a: 1, b: 2 },
{ b: 2, a: 1 },
{ a: 1, b: 2, c: { a: 1, b: 2 } },
{ a: 1, b: 2, c: { b: 2, a: 1 } }
]
显然, 这里和Set去重的输出一致, 统一无法实现对象数组去重
*/
这里的方法的核心在于:
newArr02[i]
===newArr02[j]
, 如需修改判断去重的逻辑, 修改此处即可
// 创建数组的副本,避免修改原始数组
const newArr03 = [...arr];
// 辅助函数,判断一个值是否为对象
const isObject = (obj) => typeof obj === 'object' && obj!== null;
// 通过自定义 equals 函数来比较数组中的元素,并去除重复元素, 实现灵活去重
for(let i=0;i<newArr03.length;i++){
for(let j=i+1;j<newArr03.length;j++){
if(equals(newArr03[i],newArr03[j])){ //
newArr03.splice(j,1);
j--;
}
}
}
/**
* 比较两个值是否相等。
* 如果两个值都是对象,则比较它们的属性是否相等。
* 如果两个值不是对象,则直接比较它们的值是否相等。
*
* @param {any} val01 - 要比较的第一个值。
* @param {any} val02 - 要比较的第二个值。
* @return {boolean} - 如果两个值相等,返回 true,否则返回 false。
*/
function equals(val01,val02){
if(isObject(val01) && isObject(val02)){
const keys01 = Object.keys(val01);
const keys02 = Object.keys(val02);
// 如果两个对象的键的数量不同,则它们不相等
if(keys01.length!== keys02.length){
return false;
}
// 遍历第一个对象的所有键
for(const k of keys01){
// 如果第二个对象不包含当前键,或者对应的值不相等,则它们不相等
if(!keys02.includes(k) ||!equals(val01[k], val02[k])){
return false;
}
}
// 如果所有键和对应的值都相等,则两个对象相等
return true;
}else{
// 如果两个值不是对象,则直接比较它们的值
return val01 === val02;
}
}
// 打印去重后的数组
console.log(newArr03);
/** 输出
[ { a: 1, b: 2 }, { a: 1, b: 2, c: { a: 1, b: 2 } } ]
通过自定义的equals方法实现了对象数组去重
*/
最后, 总结JavaScript中比较常见的9种数组去重方法:
- 利用
Set()
去重:代码简洁,不考虑兼容性,无法去掉 {} 空对象。 - for 嵌套 for 结合
splice
去重:双层循环,外层循环元素,内层比较值,{}、NaN 无法去重,两个 null 消失。 - 利用
indexOf
去重:新建空结果数组,通过判断是否存在当前元素决定是否添加,{}、NaN无法去重。 - 利用
sort()
去重:先排序再比对相邻元素,{}、NaN无法去重。 - 利用
includes()
去重:通过检测数组是否有某个值进行去重,{}无法去重。 - 利用
hasOwnProperty
去重:利用对象属性判断,所有元素都能去重。 - 利用
filter
去重:通过索引比对去重,{}无法去重。 - 利用递归去重:通过递归和排序进行去重,{}、NaN 无法去重。
- 利用
Map()
去重:创建 Map 存储 key 值实现去重, {}、NaN无法去重。