1. ES6 新增的 Set() 方法
优点:能处理 NaN
缺点:处理不了引用数据类型
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr) {
// 判断入参是否为数组
if(!Array.isArray(arr)) return
// 先利用 Set 方法去重,再利用扩展运算符把 Set 对象转成数组
const newArr = [...new Set(arr)]
return newArr
}
noRepeat(arr1) // [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false, NaN]
noRepeat(arr2) // [1, 3, 5, [1], [1], {}, {}, 7, 9]
2. ES6 新增的 Map() 方法
优点:能处理 NaN
缺点:处理不了引用数据类型
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr) {
if(!Array.isArray(arr)) return
let map = new Map();
let newArr = [];
for (let i = 0; i < arr.length; i++) {
// 利用 Map() 对象不允许键重复的特性,把数组的参数作为 Map 对象的键来去重
if (!map.has(arr[i])) {
map.set(arr[i], '');
newArr.push(arr[i]);
}
}
return newArr;
}
noRepeat(arr1) // [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false, NaN]
noRepeat(arr2) // [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
3. reduce 和 includes 搭配使用
优点:能处理 NaN
缺点:依然处理不了引用数据类型
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr) {
if(!Array.isArray(arr)) return
const newArr = arr.reduce((unique, currentItem) => unique.includes(currentItem) ? unique : [...unique, currentItem], [])
return newArr
}
noRepeat(arr1) [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false, NaN]
noRepeat(arr2) // [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
4. filter 和 indexOf 搭配使用
缺点:丢失 NaN 值,也不能处理引用数据类型
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr) {
if(!Array.isArray(arr)) return
const newArr = arr.filter((item, index, array) => array.indexOf(item) === index)
return newArr
}
noRepeat(arr1) // [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false]
noRepeat(arr2) // [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
5. for 循环搭配 IndexOf(for 循环搭配 includes 跟此方法类似)
缺点:不能去掉重复的 NaN 值,也不能处理引用数据类型
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr) {
if(!Array.isArray(arr)) return
let newArr = []
for(let i = 0; i < arr.length; i++) {
// 在循环中判断新数组中是否存在该值,不存在的话就 push 进新数组
if(newArr.indexOf(arr[i]) === -1) newArr.push(arr[i])
}
// 返回新数组
return newArr
}
noRepeat(arr1) // [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false, NaN, NaN]
noRepeat(arr2) // [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
6. 双层 for 循环 和 splice 搭配使用
缺点:不能去掉重复的 NaN 值,也不能处理引用数据类型
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr){
if(!Array.isArray(arr)) return
for(let i = 0; i < arr.length; i++){
for(let j = i +1; j < arr.length; j++){
if(arr[i] === arr[j]){
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
noRepeat(arr1) // [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false, NaN, NaN]
noRepeat(arr2) // [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
7. 使用 sort 和 for 循环搭配使用
缺点:不能去掉重复的 NaN 值;会打乱原有数组的顺序;当数组中存在引用数据类型时,会有 bug
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
function noRepeat(arr){
if(!Array.isArray(arr)) return
arr = arr.sort()
let newArr = [];
for(let i = 0; i < arr.length; i++){
if(arr[i] !== arr[i + 1]) newArr.push(arr[i])
}
return newArr;
}
noRepeat(arr1) // [1, 3, 4, 5, 7, 8, NaN, NaN, false, null, 'null', null, true, 'true']
noRepeat(arr2) // [1, [1], [1], 1, 3, 5, 7, 9, {}, {}]
8. 使用对象键值法
优点:可以去掉引用数据类型,但是还有点 bug
const arr1 = [1, 3, 5, 7, 3, 4, 5, 7, 8, null, 'null', true, 'true', false, false, NaN, null, null, NaN]
const arr2 = [1, 3, 5, [1], [1], {}, {}, 5, 7, 9, 1]
const arr3 = [{}, {name: 'banana'}, [1, 2], 2, 4, {}, [{age: 18, name: 'banana'}], [1, 2], {name: 'banana'}, {}]
function noRepeat(arr){
if(!Array.isArray(arr)) return
let obj = {}, newArr = [];
for(let i = 0; i < arr.length; i++) {
const currentArr = arr[i]
const type = typeof currentArr
if(!obj[currentArr]) {
obj[currentArr] = [type]
newArr.push(currentArr)
}else if(obj[currentArr].indexOf(type) <0) {
obj[currentArr].push(type)
newArr.push(currentArr)
}
}
return newArr
}
noRepeat(arr1) // [1, 3, 5, 7, 4, 8, null, 'null', true, 'true', false, NaN]
noRepeat(arr2) // [1, 3, 5, [1], {}, 7, 9]
noRepeat(arr3) // [{}, [1, 2], 2, 4] 此处由 bug
汇总:
- 如果数组中的参数不包含 NaN 值和引用数据类型,那以上的方法都适用
- 如果要处理简单数据类型和 NaN 值,优先考虑使用方法1(Set() 方法)、方法2(Map() 方法)、方法3(reduce 和 includes 搭配使用)
- 如果要处理简单的引用数据类型,优先考虑方法8(使用对象键值法)
上面方法如有误,请帮忙指出来,谢谢~