搞不定JavaScript的数组去重?你可能漏了这两个坑

  • 搞不定JavaScript的数组去重?你可能漏了这两个坑*

引言

数组去重是JavaScript开发中的常见需求,看似简单,却暗藏玄机。许多开发者认为用Set或filter就能轻松搞定,但实际场景中可能会遇到意想不到的"坑"。本文将从底层原理出发,深入剖析两个容易被忽略的数组去重问题:引用类型的去重 和特殊值的去重。通过对比不同方法的优劣,帮助你写出更健壮的代码。

主体

1. 基本方法回顾:为什么Set和filter有时会失效?

最常见的数组去重方法是使用Set或filter结合indexOf:

javascript 复制代码
// 方法1:Set
const uniqueArray = [...new Set(array)];

// 方法2:filter + indexOf
const uniqueArray = array.filter((item, index) => array.indexOf(item) === index);

这两种方法对基本类型(如number、string、boolean)表现良好,但在以下场景中会失效:

  • 引用类型去重 :Set和indexOf通过严格相等(===)比较,两个内容相同的对象会被视为不同。
  • 特殊值去重 :NaN、null、undefined等值在去重时可能表现异常。

2. 第一个坑:引用类型的去重

假设数组包含对象或数组:

javascript 复制代码
const arr = [{ a: 1 }, { a: 1 }, [1, 2], [1, 2]];
const uniqueArr = [...new Set(arr)]; // 无效!

此时,Set无法去重,因为{ a: 1 } === { a: 1 }为false。

解决方案:深度比较或序列化
  • 深度比较 :使用lodash的isEqual或自定义递归比较函数,但性能较差。
  • 序列化:将对象转为JSON字符串去重,再转回对象:
javascript 复制代码
const uniqueArr = Array.from(
  new Set(arr.map(item => JSON.stringify(item)))
).map(item => JSON.parse(item));
  • 局限性*:
  • 对象属性顺序变化会导致误判({a:1, b:2}和{b:2, a:1}被视为不同)。
  • 无法处理包含循环引用的对象。

3. 第二个坑:特殊值的去重

JavaScript中某些值的比较行为特殊:

  • NaN :NaN === NaN为false,导致Set和indexOf无法去重。
  • +0和-0 :+0 === -0为true,但某些场景需要区分。
  • null和undefined:需明确是否需要区分。
解决方案:自定义比较函数

针对NaN:

javascript 复制代码
const arr = [1, NaN, 2, NaN];
const uniqueArr = arr.filter((item, index) => {
  return arr.findIndex(i => (Number.isNaN(i) && Number.isNaN(item)) || i === item) === index;
});

针对+0和-0:

javascript 复制代码
const arr = [+0, -0, 0];
const uniqueArr = [...new Set(arr)]; // 无法区分
const uniqueArr = arr.filter((item, index) => {
  return arr.findIndex(i => Object.is(i, item)) === index; // 区分+0和-0
});

4. 性能与兼容性权衡

方法 优点 缺点
Set 简洁、高效 不兼容IE11,无法处理引用类型
filter + indexOf 兼容性好 时间复杂度O(n²),性能差
序列化 支持引用类型 性能低,有局限性
自定义比较 灵活、精准 实现复杂
  • 现代浏览器 :优先使用Set。
  • 兼容性要求高 :结合filter和findIndex。
  • 复杂场景 :使用lodash的uniqBy或uniqWith。

5. 最佳实践

  • 明确需求 :是否需要区分+0/-0?是否需要深度比较对象?
  • 性能优化:大数据量时避免递归或嵌套循环。
  • 测试覆盖 :针对NaN、null、引用类型编写单元测试。

总结

数组去重并非"一招鲜"问题。Set和filter虽简单,但无法覆盖引用类型和特殊值的场景。理解JavaScript的相等比较机制(===、Object.is、JSON.stringify)是解决问题的关键。在实际开发中,应根据需求选择最适合的方法,并通过测试确保逻辑正确性。

希望本文能帮助你避开这两个"坑",写出更健壮的数组去重代码!

相关推荐
今年下半年几秒前
AI智能体项目实战记录(02):初始化 Python 项目
开发语言·人工智能·python·fastapi
Jlzn88883 分钟前
华东电芯分选通道数怎么配才不堵线
java·人工智能·架构·自动化·制造
u13013010 分钟前
GitHub 热榜项目:日榜(2026-10-17)
人工智能·github
流烟默16 分钟前
MCP第 5 篇:用 Spring AI 写 MCP:注解、自动配置、ChatClient 集成
人工智能·spring·mcp封装
康实训18 分钟前
老年评估仿真实训平台架构设计与老年人能力评估实训室教学落地实践
大数据·人工智能·算法·实训室·实训室建设
misty youth24 分钟前
Agent-智能体工程方法论
人工智能·ai·llm·agent·智能体
lisw0525 分钟前
制造业信息化:现代工业的发展趋势!
大数据·网络·人工智能
AllData公司负责人28 分钟前
AllData搭建大模型资产中台集成开源项目BISHENG/Crater/Coze-Studio/Coze-Loop/DataFIow,建设AI大模型开发底座
大数据·人工智能·开源·bisheng·coze-studio·crater·datafiow
DongQiShanRen32 分钟前
六根硬件映射(四):归属澄清、两处不一致与卷十一总表
开发语言·人工智能·算法·rust·哈希算法·集成学习
CCblandy35 分钟前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构