浅谈JS数组去重

示例数组

1
const baseArr = [1, 1, '1', '1', 2, true, 'true', false, false, null, null, {}, {}, [], [], undefined, undefined, NaN, NaN]

ES6 的 Set 去重

Set数据类似于数组,但是成员的值都是唯一的,没有重复的值。它可以接收一个数组,类于:let a=[1,2,3,1,2] Set(a)=>1,2,3 所以可以使用Set()实现去重。

1
2
3
4
5
const resultArr = [ ...new Set(baseArr) ]
// 或者
const resultArr = Array.from(new Set(baseArr))

console.log(resultArr) // [1, "1", 2, true, "true", false, null, {}, {}, [], [], undefined, NaN]

Set内部判断两个值是否不同,使用的算法叫做“Same-value equality”,它类似于精确相 等运算符( === ),主要的区别是 NaN 等于自身,而精确相等运算符认 为 NaN 不等于自身。 另外,两个对象总是不相等的。

优点:简洁方便,可以区分NaN

缺点:无法识别相同对象和数组;

简单的场景建议使用该方法进行去重

最基础的去重:双重遍历

定义一个新数组,并存放原数组的第一个元素,然后将源数组一一和新数组的元素对比,若不同则存放在新数组中。

不处理数组中对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function unique(arr) {
let resultArr = []
for (let i = 0; i < arr.length; i++) {
let repeat = false
for (let j = i+1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
repeat = true
break
}
}
if (!repeat) {
resultArr.push(arr[i])
}
}
return resultArr
}
console.log(unique(baseArr)) // [1, "1", 2, true, "true", false, null, {}, {}, [], [], undefined, NaN, NaN]

缺点:无法识别相同对象和数组,还有NaN

处理数组中对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function unique(arr) {
let resultArr = []
for (let i = 0; i < arr.length; i++) {
let repeat = false
for (let j = i+1; j < arr.length; j++) {
if (JSON.stringify(arr[i]) === JSON.stringify(arr[j])) {
repeat = true
break
}
}
if (!repeat) {
resultArr.push(arr[i])
}
}
return resultArr
}
console.log(unique(baseArr)) // [1, "1", 2, true, "true", false, {}, [], undefined, NaN]

优点:可以区分对象和数组;

缺点:代码较复杂,不能区分 null

使用indexOf

建立一个新的空数组,遍历源数组,往这个空数组里塞值,每次 push 之前,先判断是否已有相同的值。

1
2
3
4
5
6
7
8
9
10
11
12
function unique(arr) {
if (!Array.isArray(arr)) return
let resultArr = []
for (let i = 0; i < arr.length; i++) {
if (resultArr.indexOf(arr[i]) < 0) {
resultArr.push(arr[i])
}
}
return resultArr
}

console.log(unique(baseArr)) // [1, "1", 2, true, "true", false, null, {}, {}, [], [], undefined, NaN, NaN]

优点:ES5中常用方法,兼容性高,易于理解

缺点:无法识别相同对象和数组,也不能区分 NaN

使用 ES6 的 includes

indexOf类似,但inculdes是ES2016新增API

1
2
3
4
5
6
7
8
9
10
11
12
function unique(arr) {
if (!Array.isArray(arr)) return
let resultArr = []
for (let i = 0; i < arr.length; i++) {
if (!resultArr.includes(arr[i])) {
resultArr.push(arr[i])
}
}
return resultArr
}

console.log(unique(baseArr)) // [1, "1", 2, true, "true", false, null, {}, {}, [], [], undefined, NaN]

优点:相对于 indexOf,可以区分 NaN

缺点:无法识别相同对象和数组

利用reduce+includes

两个高阶函数的巧妙使用

1
2
3
const reducer = (prev, cur) => prev.includes(cur) ? prev : [...prev, cur]
const resultArr = baseArr.reduce(reducer, [])
console.log(resultArr) // [1, "1", 2, true, "true", false, null, {}, {}, [], [], undefined, NaN]

优点:代码极简,可以区分 NaN

缺点:无法识别相同对象和数组

-------------本文结束感谢您的阅读-------------