javascript数组递归去重分三类:1.基础版用includes判断原始值;2.自定义比较版用some+回调处理对象;3.尾递归版以索引代替解构提升稳定性,但需注意栈溢出与性能问题。

JavaScript 数组去重用递归实现,核心思路是:每次取数组第一个元素,检查它是否已在结果中出现;没出现就加入结果,然后对剩余元素递归处理。这种方式逻辑清晰,但要注意避免修改原数组、防止栈溢出(大数组慎用),且需明确“去重”依据(默认按 === 比较)。
基础递归去重(适用于简单类型)
适用于数字、字符串、布尔值等原始值。递归函数接收当前数组和已收集的唯一值(作为累积器),逐步剥离首项并判断是否保留。
示例代码:
function unique(arr, result = []) {
if (arr.length === 0) return result;
const [first, ...rest] = arr;
if (!result.includes(first)) {
result.push(first);
}
return unique(rest, result);
}
// 使用
console.log(unique([1, 2, 2, 3, 1])); // [1, 2, 3]
支持自定义比较的递归去重
当数组含对象或需按特定字段去重(如 {id: 1})时,可传入比较函数。递归中不再用 includes,而是用 some 配合回调判断是否已存在。
- 比较函数接收两个参数(当前项与结果中的某一项),返回
true表示视为重复 - 递归体保持不变:取首项 → 判断 → 累加 → 递归余下部分
示例:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
function uniqueBy(arr, compareFn, result = []) {
if (arr.length === 0) return result;
const [first, ...rest] = arr;
const isDuplicate = result.some(item => compareFn(first, item));
if (!isDuplicate) result.push(first);
return uniqueBy(rest, compareFn, result);
}
// 按对象 id 去重
const list = [{id: 1}, {id: 2}, {id: 1}];
console.log(uniqueBy(list, (a, b) => a.id === b.id));
// [{id: 1}, {id: 2}]
尾递归优化(需注意环境支持)
标准 JavaScript 引擎不普遍支持尾调用优化(TCO),但写成尾递归形式更易理解且部分环境(如 Safari)可能优化。关键点是:递归调用必须是函数的最后一个操作,且不依赖当前作用域其他变量。
- 把中间状态(如
result和index)作为参数传入,避免闭包累积 - 用索引代替解构,减少内存开销(尤其对大数组)
示例(索引版,更稳妥):
function uniqueTail(arr, index = 0, result = []) {
if (index >= arr.length) return result;
const current = arr[index];
if (!result.includes(current)) {
result.push(current);
}
return uniqueTail(arr, index + 1, result);
}
注意事项与替代建议
递归去重适合教学或小数据场景,但实际项目中需权衡:
-
性能:递归调用栈深,数组超千项可能触发栈溢出;
includes在每次递归中遍历 result,时间复杂度 O(n²) -
可读性:相比
[...new Set(arr)]或filter((v, i) => arr.indexOf(v) === i),递归稍显冗长 -
引用类型:直接比较对象会失败,必须配合
compareFn,否则所有对象都被视为不重复
若只是快速去重,优先用 Set;若需兼容旧环境且逻辑复杂,再考虑递归,并限制输入规模。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










