搞不定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)是解决问题的关键。在实际开发中,应根据需求选择最适合的方法,并通过测试确保逻辑正确性。

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

相关推荐
small_wh1te_coder5 分钟前
字节技术总监30讲 AI课:3概率、信息论与损失函数|从Logits到Cross-Entropy带你吃透大模型训练
人工智能
云表无代码开发6 分钟前
日本开发者彻底破防:中文太强了!换成英文直接裂开
大数据·服务器·人工智能·microsoft·信息可视化
data analyse 45613 分钟前
报表能自定义的国内统计工具有哪些
前端·数据分析
致Great18 分钟前
不止自动写论文!谷歌 ScientistTwo 让 AI 自己做实验、补消融、回审稿
人工智能·深度学习·机器学习
XMAIPC_Robot19 分钟前
CODESYS 实时控制 + RK182X 大模型算力扩展|RK3576 工业边缘控制器设计
人工智能·fpga开发·机器人·rk3588+fpga
迪飞特科技21 分钟前
【无标题】
android·人工智能·本地化大模型
anda010929 分钟前
A2UI 协议: AI 直接画界面,而不是只会打字
人工智能·ai编程
IT_陈寒31 分钟前
JavaScript闭包的这个坑,我居然今天才爬出来
前端·人工智能·后端
张3蜂31 分钟前
Laya、Kev、NanoJev调用体验
人工智能