JS中reduce去重核心是用accumulator作已见元素容器,基础写法用includes判断并push;对对象/NaN不可靠,推荐用外部Set辅助实现O(1)查重;对象数组需按字段(如id)判重,避免引用比较。

JS 中用 reduce 配合 accumulator 去重,核心是让 accumulator 作为“已见过的元素容器”,一边遍历一边判断是否已存在,只把新元素加进去。
基础写法:返回新数组(不修改原数组)
accumulator 初始化为空数组 [],每次检查当前元素是否已在 accumulator 中,不在才 push 进去:
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = arr.reduce((acc, curr) => {
if (!acc.includes(curr)) {
acc.push(curr);
}
return acc;
}, []);
// => [1, 2, 3, 4, 5]
⚠️ 注意:includes 对对象或 NaN 不可靠([NaN].includes(NaN) 返回 true,但这是特例;对象比较永远是 false),适合简单类型(数字、字符串、布尔值)。
更健壮的写法:用 Set 辅助判重
避免 includes 的性能和语义问题,可在 reduce 外部维护一个 Set 记录已见元素:
const arr = [1, 2, 2, 3, 'a', 'a', null, null];
const seen = new Set();
const unique = arr.reduce((acc, curr) => {
if (!seen.has(curr)) {
seen.add(curr);
acc.push(curr);
}
return acc;
}, []);
// => [1, 2, 3, 'a', null]
✅ 优势:O(1) 查找、正确处理 null 和基本类型;❌ 缺点:引入了外部变量,reduce 不再完全纯函数化。
一行式写法(仅限简单场景)
利用 Set 构造器 + 扩展运算符可极简去重,但这不是 reduce 实现 —— 如果硬要用 reduce 模拟,可这样写(仍依赖 Set):
const arr = [1, 2, 2, 3]; const unique = arr.reduce((acc, curr) => acc.some(x => x === curr) ? acc : [...acc, curr], []);
⚠️ 不推荐:每次用 some + 展开数组,时间复杂度 O(n²),大数据量时明显变慢。
对象数组按某字段去重
比如按 id 去重,用 Set 存已见 id,更清晰安全:
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice2' },
{ id: 3, name: 'Charlie' }
];
const seenIds = new Set();
const uniqueUsers = users.reduce((acc, user) => {
if (!seenIds.has(user.id)) {
seenIds.add(user.id);
acc.push(user);
}
return acc;
}, []);
// => [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
关键点:用辅助 Set 管理“已存在”的依据(id、name 或其他键),而非直接比对象引用。











