一、利用ES6 Set去重(ES6中最常用)
function unique (arr) {
return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
不考虑兼容性,这种去重的方法代码最少。但这种方法还无法去掉“{}”空对象。
NaN与其他任何值比较都将不相等 ( 包括与其他 NAN值进行比较)。对象因为存放地址不同,但是从”值“上来说相同的话是否定义为”重复“?
NaN == NaN; //false
NaN === NaN; //false
{} == {}; //false
{} === {}; //false
下文的方法将按照算作“重复”这一点来分析。
二、Map去重
function unique(arr) {
let map = new Map();
let array = new Array(); // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if(!map .has(arr[i])) { // 如果有该key值
map .set(arr[i], true);
array .push(arr[i]);
}
}
console.log(map)
return array ;
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
不足点:{}没有去重
优化代码,实现全部去重:
function unique(arr){
let map=new Map()
let array=new Array()
for(let i=0;i<arr.length;i++){//-------------新增部分----------
if(typeof arr[i]==='object'){//判断是否是对象
let a=JSON.stringify(arr[i])//JSON序列化变成字符串
if(!map.has(a)){//map判别是否存在{}字符而不是{}对象
map.set(a,true)
array.push(arr[i])
}
}else{//---------------------
if(!map.has(arr[i])){
map.set(arr[i],true)
array.push(arr[i])
}
}
}
return array
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{} ];
console.log(unique(arr))
输出结果:
三、一些常用但是存在部分类型未能去重的方法:
1、利用for嵌套for,然后splice去重(ES5中最常用)
NaN和{}没有去重
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){
//第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]
// NaN和{}没有去重,两个null直接消失了
2、利用indexOf去重
NaN和{}没有去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}]
// NaN、{}没有去重
3、利用sort()
NaN和{}没有去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined]
//NaN、{}没有去重
4、利用对象的属性不能相同的特点进行去重
两个true直接去掉了,NaN和{}去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var arrry= [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
arrry.push(arr[i])
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}]
//两个true直接去掉了,NaN和{}去重
5、利用hasOwnProperty
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
var arr = [1,1,'true','true',true,true,15,15,false,false,
undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}]
// 利用hasOwnProperty 判断是否存在对象属性
虽然所有的都去重了,但是对象都会被去重
这个是 typeof 那行导致的。
所有对象的原始类型的值都是[object Object],所以所有对象转为字符串都是"[object Object]"。
那么就导致:
var obj1 = {};
typeof (obj1) + obj1 ==>"object" + obj1 ==> "object[object Object]"
var obj2 = {a:1}
typeof (obj2) + obj2 ==>"object" + obj2 ==> "object[object Object]"
其他引用类型则没有这个问题:
var fn = function(){return true};
typeof(fn) + fn ==> "functionfunction() {return true}"
var arr = [1];
typeof(arr) + arr ==> "object1"
所以,该方法遇到对象就GG。
但是,建议不要用typeof进行判断,这个对引用类型判断都会返回 object (除了function/regexp返回 "function")。
而用 Object.prototype.toString.call(value) 来进行判断会更准确些:
Object.prototype.toString.call([]) ==> "[object Array]"
当然,这也改变不了在这个方法中,两个以上不同的对象冲突的问题:
var obj1 = {};
Object.prototype.toString.call(obj1) + obj1 ==> "[object Object][object Object]"
var obj2 = {a:1};
Object.prototype.toString.call(obj2) + obj2 ==> "[object Object][object Object]"