数组去重

Set方法

1
2
3
let arr = [1, 2, 2, 3, 3, 4, 5]

console.log([...new Set(arr)]) //[1, 2, 3, 4, 5]

indexOf

1
2
3
4
5
6
7
8
9
10
let arr = [1, 2, 2, 3, 3, 4, 5]
let newArr = []

arr.forEach(item => {
if(newArr.indexOf(item) === -1) {
newArr.push(item)
}
})

console.log(newArr) //[1, 2, 3, 4, 5]

正常情况下使用这种方式没问题,但是当arr中有NaN时:

1
2
3
4
5
6
7
8
9
10
let arr = [1, 2, 2, 3, 3, 4, 5, NaN, NaN]
let newArr = []

arr.forEach(item => {
if(newArr.indexOf(item) === -1) {
newArr.push(item)
}
})

console.log(newArr) //[1, 2, 3, 4, 5, NaN, NaN]

结果与预期的不符,因为indexOf判断NaN时,结果始终为-1

我们可以使用includes进行判断,includes会正确判断NaN,但是与Object.is()表现不同的是+0-0includes判断+0-0true

关于Object.is()请查看:在相等比较中使用 Object.is()让结果更准确

1
2
3
4
5
6
7
8
9
10
let arr = [1, 2, 2, 3, 3, 4, 5, NaN, NaN]
let newArr = []

arr.forEach(item => {
if(!newArr.includes(item)) {
newArr.push(item)
}
})

console.log(newArr) //[1, 2, 3, 4, 5, NaN]

使用对象Key

1
2
3
4
5
6
7
8
9
10
11
12
let arr = [1, 2, 2, 3, 3, 4, 5, NaN, NaN]
let newArr = []
let obj = {}

arr.forEach(item => {
if(!obj[item]) {
obj[item] = true
newArr.push(item)
}
})

console.log(newArr) //[1, 2, 3, 4, 5, NaN]

但是如果下面的情况,使用这种方式就会有问题:

1
2
3
4
5
6
7
8
9
10
11
12
let arr = [1, 2, 2, 3, 3, 4, 5, '5', NaN, NaN]
let newArr = []
let obj = {}

arr.forEach(item => {
if(!obj[item]) {
obj[item] = true
newArr.push(item)
}
})

console.log(newArr) //[1, 2, 3, 4, 5, NaN]

我们发现'5'被过滤掉了,因为Object的会把key默认转换成字符串,所以识别5时,会当成'5'处理,所以再判断'5'时,对象中已经存在。

对于这样的情况,我们可以使用ES6的Map结构。

1
2
3
4
5
6
7
8
9
10
11
12
let arr = [1, 2, 2, 3, 3, 4, 5, '5', NaN, NaN]
let newArr = []
let obj = new Map()

arr.forEach(item => {
if(!obj.has(item)) {
obj.set(item,true)
newArr.push(item)
}
})

console.log(newArr) //[1, 2, 3, 4, 5, "5", NaN]

我们看到Map并没有把5转换成'5'

关于Map更多了解,请查看:Set 和 Map 数据结构