数组去重关键在“谁去重”和“按什么规则”,前端仅处理可控的临时重复,如多点按钮、多源聚合、多选清理;基础类型用Set(兼容IE11用Array.from),对象数组按唯一字段用Map去重,禁用JSON.stringify;需结合防抖、空数组校验与提示形成防护链。

数组去重本身不依赖前后端交互时机,关键在于“谁去重”和“按什么规则去重”。前端在数据交互前做去重,不是为了替代后端逻辑,而是为避免无效请求、提升用户体验、防止重复提交或渲染异常。规范做法要分清场景、数据类型和责任边界。
明确去重责任:前端只处理“可控且必要”的重复
前端不应承担业务级去重(如用户重复注册、订单重复创建),这类必须由后端校验并拒绝。前端去重仅适用于:
- 用户本地操作产生的临时重复,比如多次点击“添加标签”按钮导致数组推入相同字符串
- 前端聚合多个来源数据(如搜索建议 + 历史记录)时的简单合并去重
- 表单多选控件中用户反复勾选同一项,需实时清理输入值
- 为减少无意义请求,对即将发给后端的 ID 列表、筛选条件等做预处理
基础类型数组:优先用 Set,兼顾 NaN 和兼容性
对于 number / string / boolean / null / undefined / NaN 等基本类型,Array.from(new Set(arr)) 是最规范简洁的方式。Set 使用 SameValueZero 算法,能正确识别 NaN === NaN,这是 indexOf 或 includes 做不到的。
注意两点:
- 若需兼容 IE11 等旧环境,改用
Array.from(new Set(arr))(比扩展运算符[...new Set(arr)]兼容性更好) - Set 不会把
1和'1'当作重复——这是合理行为。若业务要求强制类型宽松去重(如接口字段全为字符串),应先统一转类型再 Set
对象数组:按字段去重,禁用 JSON.stringify 简单对比
遇到 [{id: 1, name: 'a'}, {id: 1, name: 'b'}] 这类数据,不能直接用 Set 或 filter + indexOf —— 它们比较的是引用,不是内容。
规范做法是基于唯一业务字段(如 id、skuCode)去重:
- 用 Map 记录已出现的 key 值:
arr.filter(item => !map.has(item.id) && map.set(item.id, true)) - 确保字段存在且非空,可加保护:
item.id != null - 避免使用
JSON.stringify(item)做键名:属性顺序不保证、undefined 被忽略、函数丢失、循环引用报错,线上极易翻车
交互前校验:结合防抖+去重+提示,形成完整防护链
单纯去重不够。例如用户快速点击“提交”按钮多次,即使数组去重了,仍可能并发发出多个请求。规范流程应包含:
- 前端收集数据后,先按业务规则去重(如过滤掉重复的 tagId)
- 对请求动作加防抖或节流(尤其搜索、筛选类接口)
- 提交前检查数组长度是否为 0,避免空数组请求(后端可能不校验)
- 去重后如有丢弃项,可轻量提示:“已自动合并重复项”(非必须,视 UX 要求)
不复杂但容易忽略











