javascript set(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在 JavaScript 开发中,数据结构的选择直接影响代码的效率与可维护性。Set 是 ES6 引入的重要数据结构之一,它以简洁的方式解决了“去重”“唯一性管理”等常见场景的痛点。无论是处理用户 ID 列表、过滤重复事件,还是实现算法中的集合运算,Set 都能提供优雅的解决方案。本文将从基础概念到高级用法,结合实例深入剖析 JavaScript Set 的核心特性,帮助开发者快速掌握这一工具。


Set 是什么?为什么需要它?

1. 基本定义与核心特性

Set 是一种集合数据结构,其核心特性是 存储无序且唯一的值。与数组不同,Set 中的元素不会重复,且插入顺序不重要。

  • 无重复性:通过自动过滤重复值,开发者无需手动遍历数组去重。
  • 动态性:元素可以随时添加或删除,适合处理动态变化的数据。
  • 迭代友好:支持 for...of 循环和内置迭代器方法,方便遍历操作。

形象比喻
可以将 Set 想象成一个 超市的购物篮

  • 每个商品(元素)只能放入一次,重复的商品会被自动忽略。
  • 购物篮不关心商品的摆放顺序,只关注“是否已存在”。

2. 与数组的对比

数组允许重复元素,且索引有序;而 Set 的元素唯一且无序。例如,以下代码对比了两者的差异:

// 数组允许重复  
const arr = [1, 2, 2, 3];  
console.log(arr.length); // 输出:4  

// Set 自动去重  
const mySet = new Set([1, 2, 2, 3]);  
console.log(mySet.size); // 输出:3  

如何创建和操作 Set?

1. 构造 Set 对象

通过 new Set() 初始化空集合,或通过可迭代对象(如数组、字符串)构造:

// 空 Set  
const emptySet = new Set();  

// 通过数组初始化  
const numSet = new Set([1, 2, 3]);  

// 通过字符串初始化(字符逐个添加)  
const charSet = new Set("hello");  
console.log(charSet.size); // 输出:4(因 "h", "e", "l", "o",其中 "l" 重复)  

2. 常用操作方法

方法名描述示例代码
add(value)添加元素,若已存在则无变化,返回 Set 本身mySet.add(4);
delete(value)移除元素,返回布尔值表示是否成功mySet.delete(2);
has(value)检查元素是否存在,返回布尔值mySet.has(3); // true
clear()移除所有元素mySet.clear();

实例演示

const mySet = new Set([1, 2, 3]);  

// 添加元素  
mySet.add(4);  
console.log(mySet.size); // 4  

// 删除元素  
mySet.delete(2);  
console.log(mySet.has(2)); // false  

// 清空集合  
mySet.clear();  
console.log(mySet.size); // 0  

Set 的高级特性与实际应用

1. 迭代与遍历

Set 支持多种迭代方式,包括 for...ofkeys()values()entries()

const mySet = new Set([1, 2, 3]);  

// 使用 for...of 循环  
for (const value of mySet) {  
  console.log(value); // 输出 1, 2, 3  
}  

// 使用 values() 迭代器  
const iterator = mySet.values();  
console.log(iterator.next().value); // 1  

关键区别

  • keys()values() 返回相同结果(因为集合元素无键值对),
  • entries() 返回包含 [value, value] 的数组形式(类似对象的 entries())。

2. 集合运算:交集、并集、差集

通过结合 Set 和数组方法,可以轻松实现集合运算。例如:

const setA = new Set([1, 2, 3]);  
const setB = new Set([3, 4, 5]);  

// 并集  
const union = new Set([...setA, ...setB]); // {1, 2, 3, 4, 5}  

// 交集  
const intersection = new Set([...setA].filter(x => setB.has(x))); // {3}  

// 差集(A 中不在 B 的元素)  
const difference = new Set([...setA].filter(x => !setB.has(x))); // {1, 2}  

实战案例:用 Set 解决常见问题

案例 1:数组去重

传统数组去重需要遍历筛选,而 Set 可以一行代码实现:

const arr = [1, 2, 2, 3, 4, 4];  
const uniqueArr = [...new Set(arr)]; // [1, 2, 3, 4]  

案例 2:监听唯一事件

在事件监听场景中,避免重复绑定事件:

const eventHandlers = new Set();  

function addHandler(handler) {  
  eventHandlers.add(handler);  
}  

function removeHandler(handler) {  
  eventHandlers.delete(handler);  
}  

function triggerEvent() {  
  eventHandlers.forEach(handler => handler());  
}  

案例 3:缓存唯一键值

在缓存系统中,确保键的唯一性:

const cacheKeys = new Set();  

function addToCache(key, value) {  
  if (!cacheKeys.has(key)) {  
    cacheKeys.add(key);  
    // 存储逻辑...  
  }  
}  

Set 的局限性与替代方案

1. Set 的不足

  • 不可索引访问:无法通过 set[0] 获取元素,需依赖迭代器或转换为数组。
  • 仅支持值唯一性:对象作为元素时,即使内容相同但引用不同,也会被视为不同元素。
const obj1 = { name: "Alice" };  
const obj2 = { name: "Alice" };  
const set = new Set([obj1]);  
console.log(set.has(obj2)); // false(因对象引用不同)  

2. 替代方案:WeakSet

WeakSetSet 的弱引用版本,适合存储对象且无需显式删除(内存自动回收),但功能更受限:

  • 不能遍历、不能获取大小、仅接受对象类型。
const ws = new WeakSet();  
const obj = {};  
ws.add(obj);  
// ws.size 是无效的  

结论

JavaScript Set 通过简洁的 API 和高效的去重机制,成为现代前端开发中的关键工具。从基础的元素管理到复杂的集合运算,它提供了灵活且直观的解决方案。开发者应根据场景需求,合理选择 SetWeakSet,并结合其他数据结构(如 Map)实现更复杂的逻辑。掌握 Set 的核心特性,不仅能提升代码的可读性,还能显著优化性能,尤其在处理大数据量或实时动态数据时。

未来随着 JavaScript 生态的演进,Set 的应用场景将持续扩展,建议开发者持续关注其 API 更新与最佳实践。

最新发布