简介
说明
本文用示例介绍JavaScript去重的方法。
实际开发中,前端基本不会用到数组去重,去重一般是后端进行的。但是,面试中经常会问到数组去重的方法。
去重方法简介
去重的方法由简单到复杂依次为:
- ES6的Set
- reduce + includes
- Map类型
- filter + hasOwnProperty
- filter + includes
- 对象特性(不建议使用)
- 递归
- includes + 遍历原数组
- indexOf+遍历原数组
- 双重 for 循环 + splice
对示例的介绍
首先提供一个有重复数据的原始数组,为了全面起见,本文提供的数组如下:
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
法1:ES6的Set
简介
优点:简单。
缺点:无法对“{}”空对象进行去重(不过一般不会对象进行去重)。
法1: Set 类型 + 展开运算符
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
let arr1 = [...new Set(arr)];
console.log(arr1);
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
法2:Set 类型 + Array.from
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique (arr) {
return Array.from(new Set(arr))
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
法2:reduce + includes
简介
优点:简单。
缺点:无法对“{}”空对象进行去重(不过一般不会对象进行去重)。
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
法3:Map类型
说明
创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
缺点:无法对“{}”空对象进行去重(不过一般不会对象进行去重)。
示例
function unique(arr) {
let map = new Map();
let array = []; // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if (map.has(arr[i])) { // 如果有该key值
map.set(arr[i], true);
} else {
map.set(arr[i], false); // 如果没有该key值
array.push(arr[i]);
}
}
return array;
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
法4:filter + hasOwnProperty
说明
思想:利用hasOwnProperty 判断是否存在对象属性
优点:可以对“{}”空对象进行去重(不过一般不会对象进行去重)。
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
let obj = {};
return arr.filter(function (item, index, arr) {
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}]
法5:filter + includes
说明
思想:使用过滤器,过滤重复的元素,返回新数组。
缺点:无法对“{}”空对象进行去重(不过一般不会对象进行去重)。
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
let newArr = []
newArr = arr.filter(function (item) {
return newArr.includes(item) ? '' : newArr.push(item)
})
return newArr
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
法6:对象特性(不建议使用)
说明
思想:利用对象的属性不能相同的特点进行去重。
缺点:有缺陷,不建议使用。比如:两个true的话,会都去掉
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
let newArr = [];
let obj = {};
for (let i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
newArr.push(arr[i])
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
return newArr;
}
console.log(unique(arr));
//[1, 'true', 15, false, undefined, null, NaN, 0, 'a', {…}]
法7:递归
说明
缺点:无法对“{}”空对象进行去重(不过一般不会对象进行去重)。
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
let array = arr;
let len = array.length;
array.sort(function (a, b) { //排序后更加方便去重
return a - b;
})
function loop(index) {
if (index >= 1) {
if (array[index] === array[index - 1]) {
array.splice(index, 1);
}
loop(index - 1); //递归loop,然后数组去重
}
}
loop(len - 1);
return array;
}
console.log(unique(arr));
//[1, 'true', false, null, 0, true, 15, NaN, NaN, 'NaN', 'a', {…}, {…}, undefined]
法8:includes + 遍历原数组
说明
思想:创建新的空数组。遍历原数组,使用 includes 方法(判断是否包含某一元素,包含返回true,不包含返回false)依次遍历原数组元素,判断新数组中是否含有该元素,有则放入新数组。最后返回新数组。
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
let newArr = []
for (let i = 0; i < arr.length; i++) {
if (!newArr.includes(arr[i])) {
newArr.push(arr[i])
}
}
return newArr
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
法9:indexOf+遍历原数组
说明
思想:创建新的空数组。遍历原数组,使用 indexOf 方法(查找某个元素的位置,如果不存在就返回-1)依次遍历原数组元素,判断新数组中是否含有该元素,有则放入新数组。最后返回新数组。
示例
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i]);
}
}
return newArr;
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, NaN, 'NaN', 0, 'a', {…}, {…}]
法10:双重 for 循环 + splice
思想:双层循环,外层循环元素,内层循环比较元素值。值相同则删除。
let arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined,
null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
function unique(arr) {
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;
}
console.log(unique(arr));
//[1, 'true', true, 15, false, undefined, null, NaN, NaN, 'NaN', 0, 'a', {…}, {…}]
其他网址
JavaScript数组去重(12种方法,史上最全) - SegmentFault 思否