javascript数组去重需据数据类型选择方法:原始值用set可正确处理nan并保序;ie兼容用filter+indexof但nan失效;对象数组须按字段或json.stringify哈希去重;混合类型需自定义相等逻辑。

JavaScript 数组去重看似简单,但实际要写得既准确又健壮,必须分清数据类型、理解底层比较机制,并避开常见陷阱。不是所有“看起来一样”的值都会被当作重复——比如 1 和 "1" 不冲突,{} 和 {} 却永远不重复。
原始值数组:用 Set 最省心
数字、字符串、布尔值、null、undefined、NaN 这些都属于原始值。对它们去重,new Set(arr) 是首选:
-
一行搞定:
const unique = [...new Set(arr)]或Array.from(new Set(arr)) -
自动兼容 NaN:Set 内部使用 SameValueZero 算法,
NaN === NaN成立,所以[NaN, NaN]能正确变成[NaN] - 保留原顺序:Set 插入时按首次出现顺序记录,展开后顺序不变
原始值数组:filter + indexOf 适合需要兼容老环境
如果项目还要支持 IE,不能用 Set,可以用传统组合:
arr.filter((el, i) => arr.indexOf(el) === i)- 原理清晰:只保留“当前元素第一次出现的位置等于当前索引”的项
- 注意边界:
indexOf用的是严格相等(===),所以NaN会被漏掉——[NaN, NaN].filter(...)结果仍是[NaN, NaN]
对象数组:不能直接用 Set,得靠唯一标识
两个字面量对象 {id: 1} 和 {id: 1} 在内存中地址不同,引用不等,Set 或 indexOf 都无法识别为重复。
- 按单个字段去重(如 id):
arr.filter((item, i, a) => a.findIndex(obj => obj.id === item.id) === i) - 通用哈希法(推荐):
arr.reduce((unique, cur) => { const key = JSON.stringify(cur); return unique.has(key) ? unique : unique.set(key, cur); }, new Map()).values() - 注意 JSON.stringify 的限制:函数、undefined、Symbol、循环引用会丢失或报错,生产环境需预处理
混合类型或特殊需求:手动控制比较逻辑
当你要把 1 和 "1" 当作相同,或按深层结构判断重复时,就得自己定义“相等”:
- 例如统一转字符串再比:
arr.filter((item, i) => arr.findIndex(x => String(x) === String(item)) === i) - 或用 Lodash 的
uniqWith(arr, isEqual)借助深度比较 - 关键点:去重的本质是“定义什么是重复”,而不是套公式











