JavaScript多维嵌套数组递归去重本质是先扁平化再统一去重,或在深度遍历中做内容级判重;三类场景对应不同方案:一、基础类型用flat(Infinity)+Set;二、纯净嵌套对象用JSON.stringify去重(键序敏感);三、语义去重推荐Lodash isEqual实现O(n²)深度比对。

一、基础类型 + 简单嵌套:用 flat() + Set 最省事
适合:数组只含数字、字符串、布尔值,最多一层或两层嵌套(如 `[1, [2, 3], 4, [2, 3]]`) 说明:`flat(Infinity)` 能彻底摊平任意深度,之后就变成一维基本类型数组,`Set` 就能直接用示例:
const arr = [1, [2, 3], 4, [2, 3], [5, [6, 7]], [5, [6, 7]]];<br>const flattened = arr.flat(Infinity); // [1, 2, 3, 4, 2, 3, 5, 6, 7, 5, 6, 7]<br>const unique = [new Set(flattened)]; // [1, 2, 3, 4, 5, 6, 7]
注意:这会丢失原始嵌套结构,只保留所有叶子值的唯一集合。
二、保留结构但去重子数组:递归 + JSON.stringify(限纯净数据)
适合:嵌套中只有对象、数组、基本类型,不含函数、undefined、Date、循环引用 说明:对每个子项做 `JSON.stringify` 得到标准化字符串,用 `Set` 记录已出现的字符串,跳过重复项示例(递归去重同层子数组):
function uniqueNested(arr) {<br> const seen = new Set();<br> return arr.filter(item => {<br> const key = Array.isArray(item) || typeof item === 'object' <br> ? JSON.stringify(item)<br> : String(item);<br> if (seen.has(key)) return false;<br> seen.add(key);<br> return true;<br> });<br>}<br><br>const arr = [<br> [1, 2],<br> { a: 1 },<br> [1, 2], // 重复,会被过滤<br> { a: 1 } // 键序一致时会被认为重复<br>];<br>console.log(uniqueNested(arr)); // [[1,2], {a:1}]
⚠️ 风险:`{a:1,b:2}` 和 `{b:2,a:1}` stringify 结果不同,会被视为两个元素。
立即学习“Java免费学习笔记(深入)”;
三、真正语义去重(推荐用于复杂嵌套对象数组)
适合:需要精确判断两个对象/数组是否“内容等价”,比如接口返回的嵌套配置列表 说明:不用 `stringify`,改用深度比对(如 Lodash 的 `isEqual`),配合 Map 或 reduce 实现稳定去重示例(基于内容保留首次出现项):
import { isEqual } from 'lodash';<br><br>function deepUnique(arr) {<br> const unique = [];<br> for (const item of arr) {<br> if (!unique.some(existing => isEqual(existing, item))) {<br> unique.push(item);<br> }<br> }<br> return unique;<br>}<br><br>// 测试:<br>const arr = [<br> { id: 1, tags: ['a', 'b'] },<br> { tags: ['a', 'b'], id: 1 }, // 键序不同,但内容相同<br> [1, [2, 3]],<br> [1, [2, 3]]<br>];<br>console.log(deepUnique(arr)); // 只保留第一个,第二个被跳过
优点:无视键序、支持数组/对象嵌套、正确处理 NaN、null 等;缺点是性能 O(n²),大数据量需加缓存优化。


















