文章目录
1 双层 for 循环
var array = [1, 1, "1", "1", 1];
// 写法一
function unique(arr) {
let res = [...array];
for (let i = 0; i < res.length; i++) {
for (let j = i + 1; j < res.length; j++) {
if ((res[i] === res[j])) {
res.splice(j, 1);
j--;
}
}
}
return res;
}
// 写法二
function unique(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < res.length; j++) {
if (arr[i] === res[j]) break;
}
if (j === res.length) res.push(arr[i]);
}
return res;
}
2 for 循环 + indexOf()
使用 indexOf()
简化内层循环。
var array = [1, 1, "1", "1", 1];
function unique(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) {
res.push(arr[i]);
}
}
return res;
}
3 filter() + indexOf()
var array = [1, "1", "1", 1];
function unique(arr) {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
}
4 for 循环 + includes()
var array = [1, "1", "1", 1];
function unique(arr) {
var res = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (!res.includes(arr[i])) {
res.push(arr[i]);
}
}
return res;
}
5 reduce() + includes()
var array = [1, "1", "1", 1];
function unique(arr) {
return arr.reduce((prev, cur) => {
return prev.includes(cur) ? prev : [...prev, cur];
}, []);
}
6 sort()
var array = [1, "1", "1", 1];
function unique(arr) {
// sort():默认排序顺序是在将元素转换为字符串
var sortedArr = arr.sort();
var res = [];
for (var i = 0, len = sortedArr.length; i < len; i++) {
if (!i || sortedArr[i] !== sortedArr[i - 1]) {
res.push(sortedArr[i]);
}
}
return res;
}
ES6 语法去重
7 Set()
利用了 Set 中的元素是唯一性的特点
var array = [1, "1", "1", 1];
function unique(arr) {
return [...new Set(arr)]
}
8 Map()
var array = [1, "1", "1", 1];
function unique(arr) {
const myMap = new Map();
return arr.filter((v) => !myMap.has(v) && myMap.set(v, true));
}
特殊类型比较
原始值的比较是值的比较:
它们的值相等时它们就相等(==
);
console.log(1 == '1'); // true 两者转换成数字再比较值
它们的值和类型都相等时,它们就全等(===
);
console.log(1 === '1'); // false
console.log(1 === 1); // true
对象的比较并非值的比较,而是引用的比较:
即使两个对象包含同样的属性及相同的值,它们也是不相等的。
var obj1 = { x: 1 };
var obj2 = { x: 1 };
console.log(obj1 == obj2); // false
当且仅当它们引用同一个对象时,才会全等(===
)
var a = { x: 1 };
var b = a;
console.log(a === b); // true
其它特殊类型比较
var str1 = '1';
var str2 = new String('1');
console.log(str1 == str2); // true
console.log(str1 === str2); // false 一个数据类型为 'string',另一个数据类型为 'object'
console.log(null == null); // true:null 类型只有一个值,那就是 null 本身,所以相等(==)
console.log(null === null); // true:数据类型都是 'object'
console.log(undefined == undefined); // true:undefined 类型只有一个值,那就是 undefined,所以相等(==)
console.log(undefined === undefined); // true:数据类型都是 'undefined'
console.log(NaN == NaN); // false:NaN 等于任何值,包括自身
console.log(NaN === NaN); // false:数据类型都是 'object',但值不相等
console.log({} == {}); // false:对象是引用的比较
console.log({} === {}); // false
那么,对于这样的一个数组
var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), NaN, NaN];
上面的去重方法的结果怎么样呢?
重点关注下对象和 NaN 的去重情况
方法 | 结果 | 说明 |
---|---|---|
双层 for 循环 | [1, ‘1’, null, undefined, String, String, NaN, NaN] | 对象和 NaN 都不去重 |
for 循环 + indexOf() | [1, ‘1’, null, undefined, String, String, NaN, NaN] | 对象和 NaN 都不去重 |
filter() + indexOf() | [1, ‘1’, null, undefined, String, String] | 对象不去重,NaN 会被忽略掉 |
for 循环 + includes() | [1, ‘1’, null, undefined, String, String, NaN] | 对象不去重,NaN 去重 |
reduce() + includes() | [1, ‘1’, null, undefined, String, String, NaN] | 对象不去重,NaN 去重 |
sort() | [1, ‘1’, String, String, NaN, NaN, null, undefined] | 对象和 NaN 都不去重 |
Set() | [1, ‘1’, null, undefined, String, String, NaN] | 对象不去重,NaN 去重 |
Map() | [1, ‘1’, null, undefined, String, String, NaN] | 对象不去重,NaN 去重 |
9 Object 键值对
上面的去重方法都不能去重对象,那么如何去重属性都相同的对象呢?
我们可以利用一个空的 Object 对象,把数组的值存成 Object 的key
值,比如Object[value1] = true
,在判断另一个值的时候,如果Object[value2]
存在的话,就说明该值是重复的。
var array = [1, 2, 1, 1, "1"];
function unique(array) {
var obj = {};
return array.filter(function (item, index) {
return obj.hasOwnProperty(item) ? false : (obj[item] = true);
});
}
// [1, 2]
可以发现结果是有问题的,没能正确区分1
和'1'
,这是因为对象的键值都是字符串。
所以可以使用typeof item + item
拼成字符串作为key
值来避免这个问题。
var array = [1, 2, 1, 1, "1"];
function unique(array) {
var obj = {};
return array.filter(function (item, index) {
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true);
});
}
// [1, 2, '1']
然而,即便如此,依然无法正确区分出两个对象,比如{ value: 1 },{ value: 2 }
,因为两者typeof item + item
的结果都是object[object Object]
,不过可以使用JSON.stringify
将对象序列化。
var array = [1, 1, "1", "1", { value: 1 }, { value: 2 }, { value: 1 }, null, null, undefined, undefined, NaN, NaN];
function unique(array) {
var obj = {};
return array.filter(function (item, index) {
return obj.hasOwnProperty(typeof item + JSON.stringify(item))
? false
: (obj[typeof item + JSON.stringify(item)] = true);
});
}
// [1, '1', { value: 1 }, { value: 2 }, null, undefined, NaN]