当前位置: 首页 > news >正文

数据的“洁癖”管家:深入解析 JavaScript Set

🧊 数据的“洁癖”管家:深入解析 JavaScript Set

🤔 为什么我们需要 Set?

在开发中,我们经常遇到这样的场景:

  1. 数组去重:从后端获取了一堆标签,需要去除重复项。
  2. 快速查找:判断某个用户 ID 是否已经在黑名单中。
  3. 集合运算:求两个用户群体的交集、并集或差集。

如果使用传统的Array,这些操作往往需要嵌套循环或复杂的逻辑,代码冗长且性能低下(尤其是数据量大时)。而Set天生就是为了解决“唯一性”和“高效查找”而生的。

通俗比喻

  • Array(数组):像是一个普通的储物箱。你可以往里面扔任何东西,哪怕是一模一样的苹果,它也会照单全收。如果你想找某个苹果,你得把箱子倒出来一个个看。
  • Set(集合):像是一个带有自动识别功能的智能货架
    • 唯一性:如果你试图放入一个已经存在的苹果,货架会直接拒绝:“这个已经有了!”
    • 高效性:货架内部有索引,问你“有没有红富士?”它能瞬间回答“有”或“没有”,不需要逐个翻找。

📂 目录

  1. 🔍 核心概念与基本用法
  2. 🛠️ 常用 API 详解
  3. ⚔️ 实战场景:去重与集合运算
  4. 💡 进阶技巧:WeakSet 与性能分析
  5. ❌ 常见误区与坑点
  6. 💡 总结与选型建议

1. 🔍 核心概念与基本用法

Set本身是一个构造函数,用来生成Set数据结构。

✅ 基本创建

// 1. 创建一个空的 Setconsts1=newSet();// 2. 通过数组初始化(自动去重)consts2=newSet([1,2,3,2,1]);console.log(s2);// Set(3) { 1, 2, 3 }// 3. 通过字符串初始化(字符串也是可迭代对象)consts3=newSet("hello");console.log(s3);// Set(4) { 'h', 'e', 'l', 'o' } -> 注意 'l' 只保留了一个

⚠️ 判断相等的规则

Set内部判断两个值是否相等,使用的是“Same-value-zero”算法。

  • 它类似于严格相等运算符 (===)。
  • 主要区别:在Set中,NaN等于NaN
consts=newSet();s.add(NaN);s.add(NaN);console.log(s.size);// 1,因为 NaN === NaN 在 Set 中被视为相同s.add({});s.add({});console.log(s.size);// 3,因为两个空对象引用地址不同,被视为不同元素

2. 🛠️ 常用 API 详解

Set的实例方法非常直观,主要分为增、删、查、清四类。

方法描述返回值
add(value)添加某个值,返回 Set 结构本身(支持链式调用)Set对象
delete(value)删除某个值,返回一个布尔值,表示删除是否成功boolean
has(value)判断某个值是否存在于 Set 中boolean
clear()清除所有成员,没有返回值undefined
size属性,返回成员总数number

💻 代码示例

constmySet=newSet();// 添加元素mySet.add(1).add(2).add(2);// 链式调用,第二个 2 被忽略console.log(mySet.size);// 2// 判断存在console.log(mySet.has(1));// trueconsole.log(mySet.has(3));// false// 删除元素mySet.delete(1);console.log(mySet.has(1));// false// 清空mySet.clear();console.log(mySet.size);// 0

🔄 遍历方法

Set默认是可迭代的,可以使用for...of循环,也提供了以下遍历方法:

  • keys(): 返回键名的遍历器(对于 Set,键名即值)
  • values(): 返回键值的遍历器
  • entries(): 返回键值对的遍历器
  • forEach(): 使用回调函数遍历每个成员
constset=newSet(["red","green","blue"]);for(letitemofset){console.log(item);}// red// green// blue// 转换为数组进行高阶操作constarr=[...set];// 或者constarr2=Array.from(set);

3. ⚔️ 实战场景:去重与集合运算

这是Set最发光发热的地方。

✅ 场景一:数组去重(最经典用法)

以前我们需要用indexOffilter配合对象哈希来去重,现在一行代码搞定。

constarr=[1,2,2,3,4,4,5];// 方法:Set -> ArrayconstuniqueArr=[...newSet(arr)];// 或者constuniqueArr2=Array.from(newSet(arr));console.log(uniqueArr);// [1, 2, 3, 4, 5]

注意:这种方法只能去除基本类型的重复值。如果数组中包含对象{},由于引用地址不同,无法去重。

✅ 场景二:集合运算(交、并、差)

利用Set和数组方法,可以轻松实现数学中的集合运算。

consta=newSet([1,2,3]);constb=newSet([2,3,4]);// 1. 并集 (Union): a + bconstunion=newSet([...a,...b]);console.log(union);// Set(4) { 1, 2, 3, 4 }// 2. 交集 (Intersection): a ∩ b (既在 a 又在 b)constintersection=newSet([...a].filter((x)=>b.has(x)));console.log(intersection);// Set(2) { 2, 3 }// 3. 差集 (Difference): a - b (在 a 但不在 b)constdifference=newSet([...a].filter((x)=>!b.has(x)));console.log(difference);// Set(1) { 1 }

✅ 场景三:高性能查找

当数据量很大时,Array.includes()的时间复杂度是O(N),而Set.has()的时间复杂度接近O(1)

constlargeArray=Array.from({length:100000},(_,i)=>i);constlargeSet=newSet(largeArray);console.time("Array Search");largeArray.includes(99999);console.timeEnd("Array Search");// 较慢console.time("Set Search");largeSet.has(99999);console.timeEnd("Set Search");// 极快

4. 💡 进阶技巧:WeakSet 与性能分析

📉 WeakSet:垃圾回收的好帮手

WeakSet结构与Set类似,也是不重复值的集合。但它有两个显著区别:

  1. 成员只能是对象,不能是基本类型值。
  2. 弱引用:其中的对象如果没有其他引用,会被垃圾回收机制自动回收,不会导致内存泄漏。

适用场景:存储 DOM 节点标记、缓存对象引用等临时性数据。

constws=newWeakSet();constobj={};ws.add(obj);console.log(ws.has(obj));// trueobj=null;// 解除引用// 此时,ws 中的 obj 可能会被垃圾回收,具体取决于引擎实现

注意WeakSet不可遍历,没有size属性,也没有keys/values/entries方法。

🚀 性能对比总结

操作ArraySet优势方
查找元素O(N) (线性扫描)O(1) (哈希表)Set(数据越大优势越明显)
添加元素O(1) (末尾)O(1)平手
删除元素O(N) (需查找+移动)O(1)Set
去重需额外逻辑天然支持Set
内存占用较低略高 (哈希表开销)Array

5. ❌ 常见误区与坑点

1. 引用类型无法自动去重

consts=newSet();s.add({id:1});s.add({id:1});console.log(s.size);// 2!因为两个对象内存地址不同

解决方案:如果需要基于对象的某个属性去重,需先处理数据(如转为 JSON 字符串或使用 Map)。

2. +0 和 -0

Set中,+0-0被视为相同的值。

consts=newSet();s.add(+0);s.add(-0);console.log(s.size);// 1

3. Set 转数组的顺序

Set保持插入顺序。遍历时,先添加的元素先被遍历。这一点与某些语言中的 HashSet(无序)不同,请务必记住。


6. 💡 总结与选型建议

📝 核心总结

特性ArraySet
有序性✅ 有序✅ 有序 (插入顺序)
唯一性❌ 可重复✅ 唯一
查找速度慢 (O(N))快 (O(1))
数据类型任意任意 (WeakSet 仅限对象)
主要用途列表、栈、队列去重、快速查找、集合运算

🚀 博主寄语

  • 日常开发:遇到“去重”需求,无脑选Set[...new Set(arr)]是最优雅的写法。
  • 性能敏感:如果需要频繁判断“某元素是否存在”,请将数据存入Set而不是Array
  • DOM 操作:如果需要标记一组 DOM 元素且不担心内存泄漏问题,可以考虑WeakSet
  • 面试加分项:提到Set基于哈希表实现,所以查找效率高;提到NaN的特殊处理;提到WeakSet的垃圾回收机制。

记住口诀
数组去重用 Set,一行代码解千愁。
查找频繁建集合,哈希原理速度快。
对象引用要注意,地址不同算两个。
弱引用里存节点,内存泄漏不用忧。
交集并集差集算,Filter Has 组合秀。

希望这篇文档能帮你彻底掌握Set的用法!如果有疑问,欢迎在评论区留言。👇

喜欢这篇文章吗?记得点赞、收藏、转发哦!❤️

http://www.jsqmd.com/news/853133/

相关文章:

  • OpCore-Simplify:解析黑苹果EFI配置自动化的技术架构
  • 如何在30分钟内用OpCore-Simplify完成OpenCore EFI自动化配置?终极黑苹果简化指南
  • 毕节工作服定制全攻略:避坑指南与靠谱厂家推荐 - 贵州服装测评君
  • 2026 年吉林建筑资质服务靠谱源头机构推荐:资质代办 / 新批 / 延期 / 股权收购 / 选择指南 - 海棠依旧大
  • ncmdumpGUI:3分钟快速解密网易云音乐NCM文件的终极Windows工具
  • G-Helper深度指南:7天掌握华硕笔记本性能优化神器
  • 全志V853开发板音频系统实战:从ALSA驱动到应用开发全解析
  • 2026终极指南:用BiliTools轻松下载B站视频的完整解决方案
  • 2026 年华南体育器材优质源头厂家推荐:研发生产・场地建设・全案服务 - 海棠依旧大
  • 猫抓Cat-Catch:浏览器资源嗅探的完整实用解决方案
  • 当通信中断时,是谁在守护“生命热线”——无线电应急通讯科普 - 黑龙江单工科技
  • CANN/asc-devkit:获取按位非临时缓冲区因子大小接口文档
  • CAPL编程从入门到精通:车载网络自动化测试与仿真实战指南
  • 2026 年 5 月西安成人高考机构实测|无隐形消费优选 - 讲清楚了
  • 在Windows电脑上安装安卓APK文件的终极指南:告别臃肿模拟器
  • B站直播弹幕姬:三分钟打造智能互动直播间
  • 5分钟完成Obsidian插件汉化:i18n工具让你的英文界面秒变中文
  • 如何快速掌握SECS/GEM协议:面向初学者的完整实战指南
  • WordPress如何建站 WordPress建站公司服务费用大概多少 - 麦麦唛
  • CANN/asc-devkit逻辑或运算接口
  • VcXsrv:Windows平台终极跨平台GUI解决方案深度解析
  • 规则是如何穿上“真理”外衣_1.1公开规则 vs. 水下规则
  • 2026年的软硬两用不塌陷专业床垫,究竟好在哪?
  • 树莓派TFT LCD屏幕连接全攻略:从SPI到DPI的选型与驱动配置
  • 2026结合自动化设备数据采集系统,稼动率采集的解决方案有哪些 - 品牌企业智选官
  • 全域数理统一理论合集文档
  • 昇腾C LogicalXor临时空间大小获取
  • 3分钟掌握Blender四边形重拓扑:QRemeshify终极简单指南
  • LAV Filters终极配置指南:开源媒体解码器的专业级优化方案
  • 在Windows Hyper-V上运行macOS虚拟机的完整指南