javascript数组去重关键在于理解相等判断逻辑:基本类型首选set(支持nan、保序、o(n)),对象数组须用map按字段判重,需据数据量、兼容性、业务规则等现实约束选择方案。

从入门到熟练掌握 JavaScript 数组去重,关键不是背代码,而是理解“为什么这个方法能去重”“它在什么情况下会失效”“我该在什么场景选哪一种”。下面按认知进阶路径拆解,不堆砌 15 种写法,只聚焦真正影响开发决策的几个核心维度。
先搞懂“重复”到底指什么
JS 里没有统一的“重复”定义,不同方法依赖不同的相等判断逻辑:
-
===(严格相等):数字
1和字符串"1"不重复;NaN !== NaN,所以用indexOf或双层循环会漏掉 NaN -
SameValueZero 算法:Set 和 Map 内部使用,
NaN === NaN成立,能正确识别 NaN 为重复项 -
引用相等:两个
{}或两个[1,2]永远不重复,哪怕内容一模一样——因为它们内存地址不同
不厘清这点,后面所有方法都容易踩坑。比如你用 Array.from(new Set(arr)) 处理对象数组,结果发现一个没少,不是语法错,是语义错。
基本类型去重:4 种主力方法怎么选
对数字、字符串、布尔值、null、undefined、NaN 这类值,日常够用的就这四种,按优先级排序:
- Set + Array.from / 扩展运算符:一行解决,性能好(O(n)),保序,支持 NaN,推荐作为默认首选
- filter + indexOf:语义清晰(“只保留第一次出现的位置”),兼容性好(IE9+),但对 NaN 失效
- reduce + includes:函数式风格,可读性强,性能略低于 Set(includes 是 O(n)),适合需要链式处理的场景
-
对象键名法(obj[item] = true):快但有隐式转换——
1和"1"会被当成同一个 key,慎用于混合类型数组
对象数组去重:不能靠 Set,得靠逻辑
Set 对对象无效,必须指定“按哪个字段判重”。通用思路是用 Map 记录已出现的字段值:
- 想按
id去重:new Map()存item.id为 key,value 可设为true或直接存整个对象 - 想按多个字段(如
name + type):map.set(item.name + '|' + item.type, item) - 想保留最后出现的对象(而非第一个):把
filter换成forEach,遇到已存在 key 就覆盖 value
避免用 JSON.stringify(item) 判重——字段顺序稍有变动或多了个空格就失效,且性能差。
进阶意识:别只盯着“怎么写”,要问“为什么这么写”
熟练的标志,是你开始主动考虑这些现实约束:
-
数据量大时(>10000 条):避开
filter + indexOf(O(n²)),优先 Set 或 Map -
需要兼容 IE11:Set 需 polyfill,改用
reduce + indexOf或封装好的工具库 - 后端返回的数据结构不稳定:别硬写通用去重函数,先明确业务规则——是去重还是合并?是按 ID 还是按内容?
- 面试被问“如果数组里有函数或 Symbol 怎么办?”:说明对方在考你是否知道 Set 的 SameValueZero 能正确处理 Symbol,但函数仍按引用比较
真正的熟练,是看到需求第一反应不是翻笔记找代码,而是快速判断类型、规模、环境、边界条件,再匹配最轻量又可靠的方案。











