JavaScript数组去重需据数据类型、重复定义等决策,核心按重复判定分三类:全等比较(===)、SameValueZero(含NaN)、字段/结构提取(对象数组)。

JavaScript 数组去重不是“选一个最短写法就行”的问题,而是要根据数据类型、重复定义、性能要求、边界兼容性来决策。画思维导图的关键,是把“判断重复的逻辑”作为主线,而不是罗列函数名。
核心主干:按“重复判定方式”分层
中心节点写“JS 数组去重”,第一层只分三类本质策略: - 基于**全等比较(===)** 的去重 - 基于**SameValueZero 算法** 的去重(能正确处理 NaN) - 基于**字段/结构提取** 的去重(适用于对象数组)全等比较方案:简单但有盲区
适用场景:纯基本类型(字符串、数字、布尔)、不包含 NaN 或 null/undefined 混用 典型方法: - filter + indexOf:`arr.filter((item, i) => arr.indexOf(item) === i)` - for + includes:遍历原数组,用 includes 判断是否已存在 注意点: • `indexOf` 和 `includes` 都使用 ===,所以 `NaN` 会被漏掉(`[NaN, NaN].indexOf(NaN) === -1`) • `null` 和 `undefined` 可被正确识别为不同值(`null !== undefined`)SameValueZero 方案:真正覆盖所有基本类型
这是 Set 和 Array.from 的底层机制,能正确把两个 NaN 视为相等 典型方法: - new Set + Array.from:`Array.from(new Set(arr))` 或 `[...new Set(arr)]` - reduce + findIndex(配合 Object.is):用 `Object.is(a, b)` 替代 `===` 做比较 关键细节: • Set 构造时自动使用 SameValueZero,所以 `[NaN, NaN, 1].length === 2` • 不支持对象去重(因为对象靠引用比较,两个字面量对象永远不等)对象数组去重:必须自定义“重复标准”
不能直接套用 Set,得先提取唯一标识 常用模式: - Map + 键名去重:以某字段(如 id)为 key,value 存整个对象,最后取 values ```js const unique = [...new Map(arr.map(item => [item.id, item])).values()]; ``` - reduce + find(按字段比对):`arr.reduce((acc, cur) => acc.find(x => x.id === cur.id) ? acc : [...acc, cur], [])` 提醒: • 避免用 `JSON.stringify` 做键——顺序敏感、无法处理函数/undefined/循环引用 • 如果字段可能为空或类型不一(如 `id: 1` vs `id: "1"`),需提前归一化收尾补上易错提示
- 原地修改?`Set` 和 `filter` 都返回新数组,不影响原数组;`splice` 类操作才改原数组 - 性能差异:小数组(10000)优先用 Set(O(n)),避免嵌套循环(O(n²)) - 特殊值陷阱:`+0` 和 `-0` 在 SameValueZero 中被视为不同(`Object.is(+0, -0) === false`),但多数业务可忽略一张好的去重导图,让你一眼看出:
→ 这个数组有没有 NaN?选 Set
→ 是不是对象?看有没有唯一字段,选 Map
→ 要不要保序?filter / Set / reduce 都保序;排序去重(sort + 邻位比)不保序
不复杂但容易忽略。


















