JS数组去重可用对象属性唯一性(哈希表),基础版适用于字符串、数字,但1与"1"冲突;安全版用Map支持任意类型键;通用版对对象等用JSON.stringify转键,有局限;简洁版用filter+对象标记,仅适用基本类型。

JS 中利用对象属性的唯一性(即哈希表原理)实现数组去重,核心是把数组元素作为对象的键(key),借助对象自动去重的特性过滤重复项。这种方法适用于**字符串、数字等基本类型**,对引用类型(如对象、数组)需先转为唯一字符串标识(如 JSON.stringify),否则会失效。
基础版:仅支持字符串和数字
对象的键会被自动转为字符串,所以 1 和 "1" 会冲突;但若确保输入类型统一,就可直接使用:
function uniqueByObject(arr) {
const seen = {};
const result = [];
for (const item of arr) {
if (!seen[item]) {
seen[item] = true;
result.push(item);
}
}
return result;
}
uniqueByObject([1, 2, 2, 3, "3", 1]); // [1, 2, 3, "3"]
- 利用
seen[item]判断是否已存在(对象属性访问 O(1)) - 顺序保留,首次出现的元素进入结果
- 注意:
undefined、null、[object Object]等可能隐式转换导致误判,慎用于混合类型
安全版:处理 null / undefined / 对象等
用 Map 更稳妥(ES6+),它支持任意类型作键,且不强制类型转换:
function uniqueByMap(arr) {
const seen = new Map();
const result = [];
for (const item of arr) {
if (!seen.has(item)) {
seen.set(item, true);
result.push(item);
}
}
return result;
}
uniqueByMap([1, null, undefined, null, {a:1}, {a:1}]);
// [1, null, undefined, {a:1}, {a:1}] —— 注意:对象仍按引用判断,两个 {a:1} 被视为不同
-
Map是更现代、语义更清晰的哈希结构 - 对对象去重需额外序列化(见下一点)
- 兼容性好,主流环境均支持
通用版:支持对象/数组等复杂类型去重
对引用类型,先用 JSON.stringify 转成唯一字符串键(前提是结构规则、无函数/undefined/Symbol/循环引用):
function uniqueByStringify(arr) {
const seen = new Set(); // 或用 {},但 Set 更语义明确
const result = [];
for (const item of arr) {
const key = typeof item === 'object' && item !== null
? JSON.stringify(item)
: String(item);
if (!seen.has(key)) {
seen.add(key);
result.push(item);
}
}
return result;
}
uniqueByStringify([{x:1}, {x:1}, [1,2], [1,2]]); // [{x:1}, [1,2]]
- 用
Set存字符串 key,避免手动管理对象属性 -
JSON.stringify有局限:忽略函数、undefined、Symbol;对 Date、RegExp 返回空对象;不支持循环引用 - 生产环境建议用
lodash.uniqWith或自定义比较函数替代
简洁写法(一行式,适合简单场景)
结合 filter 和对象标记:
const unique = (arr) => {
const seen = {};
return arr.filter(item => !(item in seen) && (seen[item] = true));
};
- 利用逻辑运算符短路和赋值表达式,在 filter 中边判断边记录
- 简洁但可读性略低,不推荐在复杂逻辑中使用
- 同样只适用于字符串/数字等能安全转 key 的类型


















