JS 数组去重的8种方法,包括 NaN 和引用数据类型的去重方法

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]

ES6 新增的 Set 和 Map 详解和区别

Set() MDN 文档

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]

ES6 新增的 Set 和 Map 详解和区别

Map() MDN 文档

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]

reduce MDN 文档

includes MDN 文档

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]

filter MDN 文档
indexOf MDN 文档

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, {}, {}]

sort MDN 文档

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

汇总:

  1. 如果数组中的参数不包含 NaN 值和引用数据类型,那以上的方法都适用
  2. 如果要处理简单数据类型和 NaN 值,优先考虑使用方法1(Set() 方法)、方法2(Map() 方法)、方法3(reduce 和 includes 搭配使用)
  3. 如果要处理简单的引用数据类型,优先考虑方法8(使用对象键值法)

上面方法如有误,请帮忙指出来,谢谢~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值