提供三种javascript数组去重方案:基础版用set处理原始值;进阶版支持按字段路径或自定义函数去重对象/数组;增强版统一入口并校验输入,兼顾灵活性与健壮性。

封装一个通用的 JavaScript 数组去重工具函数,关键在于支持多种数据类型(基础值、对象、数组)、可自定义去重逻辑,并保持简洁易用。下面提供几个实用、可直接复用的方案。
基础版:适用于原始值(string/number/boolean/null/undefined)
利用 Set 最简实现,兼容性好、性能高,适合大多数场景:
function unique(arr) {
return [...new Set(arr)];
}
✅ 优点:一行核心代码,自动过滤 NaN(Set 中 NaN 只保留一个),不修改原数组。
⚠️ 注意:不能处理对象、函数、NaN 以外的特殊值(如 {} 或 [])会一律视为不同。
进阶版:支持对象/数组,通过 keyPath 或 compareFn 自定义比较
当数组含对象时,需明确“重复”的定义。常见方式有两种:
-
按字段路径去重(如
id、user.name):
function uniqueBy(arr, keyPath) {
const seen = new Map();
return arr.filter(item => {
const key = typeof keyPath === 'function'
? keyPath(item)
: keyPath.split('.').reduce((o, k) => o?.[k], item);
if (seen.has(key)) return false;
seen.set(key, true);
return true;
});
}
// 使用示例
const users = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}, {id: 1, name: 'Alicia'}];
uniqueBy(users, 'id'); // → [{id:1,name:'Alice'}, {id:2,name:'Bob'}]
uniqueBy(users, u => u.name.toLowerCase()); // 按小写姓名去重
- 传入比较函数(最灵活,支持任意结构):
function uniqueWith(arr, compareFn) {
return arr.filter((item, i) =>
arr.slice(0, i).every(prev => !compareFn(prev, item))
);
}
// 使用示例:按对象内容深比较(简易版)
uniqueWith([{a:1}, {b:2}, {a:1}], (a, b) => JSON.stringify(a) === JSON.stringify(b));
增强健壮性:处理 null/undefined 和类型安全
生产环境建议加一层校验,避免意外报错:
function unique(arr, options = {}) {
const { by, compare } = options;
if (!Array.isArray(arr)) {
console.warn('unique() expects an array');
return [];
}
if (by) return uniqueBy(arr, by);
if (compare) return uniqueWith(arr, compare);
return [...new Set(arr)];
}
这样调用更清晰:unique([1, 1, 2]);unique(users, { by: 'id' });unique(items, { compare: (a, b) => a.id === b.id && a.type === b.type });
小提醒:别踩这些坑
-
慎用 JSON.stringify 做对象去重:属性顺序不同会导致结果不同(
{a:1,b:2}≠{b:2,a:1});有函数、undefined、Symbol 会丢失。 -
Map/Set 对 NaN 的处理是正确的(它们认为所有 NaN 相等),但
===不行,所以基础版 Set 是可靠选择。 -
大数组慎用 filter + slice + every(如
uniqueWith),时间复杂度 O(n²),万级数据建议换哈希预处理或分块。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











