news 2026/6/15 12:07:28

JavaScript中的Set和Map

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript中的Set和Map

一、前言:为什么需要 Set 和 Map?

在 JavaScript 中,数组(Array)和对象(Object)是最常用的数据结构,但它们在特定场景下存在明显短板:

  • 数组查找元素需遍历,时间复杂度 O (n),且去重需额外处理;
  • 对象的键只能是字符串 /.Symbol,无法直接使用引用类型作为键,且无法快速获取键值对数量。

ES6 引入的Set(集合)和Map(映射),正是为解决这些痛点而生 —— 它们提供了更高效的查找、插入、删除操作,以及更灵活的键类型支持,成为复杂业务场景的优选数据结构。

二、Set:不重复元素的有序集合

2.1 核心特性
  • 元素唯一:自动去重,重复添加的元素会被忽略;
  • 有序存储:按插入顺序保存元素(ES6 规范),遍历顺序与插入顺序一致;
  • 支持多种类型:可存储字符串、数字、布尔值、引用类型(对象、数组等);
  • 无键名只有值:本质是 “值 - 值” 映射,可理解为 “只有键的数组”。
2.2 常用 API(含示例)

// 1. 初始化

const set = new Set([1, 2, 2, 'a', true]); // 自动去重:Set(4) {1, 2, 'a', true}

// 2. 增删改查

set.add(3); // 添加元素:Set(5) {1, 2, 'a', true, 3}

set.delete('a'); // 删除元素:返回true(成功)/false(失败)

set.has(2); // 查找元素:返回true

set.size; // 获取长度:4

set.clear(); // 清空集合:Set(0) {}

// 3. 遍历方式

const set2 = new Set(['x', 'y', 'z']);

// 方式1:for...of遍历

for (const val of set2) {

console.log(val); // x, y, z

}

// 方式2:forEach遍历

set2.forEach((val, index) => {

console.log(val); // x, y, z(index与val相同)

});

// 方式3:转换为数组

const arr = [...set2]; // ['x', 'y', 'z']

2.3 实战场景
  1. 数组去重:const uniqueArr = [...new Set(arr)];(简洁高效,时间复杂度 O (n));
  1. 数据筛选:存储不重复的 ID、标签等,如const userIds = new Set(['101', '102', '101']);;
  1. 快速判断存在性:比数组indexOf更高效(Set 查找为 O (1),数组为 O (n))。

三、Map:键值对的灵活映射

3.1 核心特性
  • 键类型无限制:可使用字符串、数字、对象、数组、Symbol 等作为键;
  • 有序存储:按插入顺序保存键值对,遍历顺序与插入顺序一致;
  • 键唯一:重复设置同一键会覆盖旧值;
  • 可迭代:支持直接遍历,无需像对象那样先获取键数组。
3.2 常用 API(含示例)

// 1. 初始化

const map = new Map([

['name', '张三'],

[18, '年龄'],

[{ id: 1 }, '用户信息'] // 对象作为键

]);

// 2. 增删改查

map.set('gender', '男'); // 添加键值对:Map(4) {['name','张三'], [18,'年龄'], [{id:1},'用户信息'], ['gender','男']}

map.get(18); // 获取值:'年龄'

map.has('name'); // 查找键:true

map.delete({ id: 1 }); // 注意:对象键是引用类型,需用同一引用才能删除

map.size; // 获取长度:3

map.clear(); // 清空映射

// 3. 遍历方式

const map2 = new Map([['a', 1], ['b', 2]]);

// 方式1:遍历键值对(最常用)

for (const [key, val] of map2) {

console.log(key, val); // a 1, b 2

}

// 方式2:遍历键/值

for (const key of map2.keys()) { /* 遍历键 */ }

for (const val of map2.values()) { /* 遍历值 */ }

// 方式3:forEach遍历

map2.forEach((val, key) => {

console.log(key, val); // a 1, b 2

});

3.3 关键注意点
  • 引用类型作为键:对象、数组等引用类型作为键时,只有引用完全一致才视为同一键:

const obj1 = { id: 1 };

const obj2 = { id: 1 };

const map = new Map([[obj1, 'test']]);

map.get(obj2); // undefined(obj1与obj2是不同引用)

  • 与对象的区别

特性

Map

Object

键类型

任意类型

字符串 / Symbol

遍历顺序

插入顺序

无序(ES6 前)

长度获取

size 属性直接获取

需手动计算(Object.keys (obj).length)

迭代性

直接迭代

需先获取键数组

四、Set 与 Map 的核心区别与选型建议

4.1 核心区别

维度

Set

Map

存储结构

单值集合(值 - 值)

键值对映射(键 - 值)

核心用途

存储不重复元素

键值对关联查询

常用操作

去重、判断存在性

键值映射、数据关联

遍历返回值

直接返回元素

返回 [key, value] 数组

4.2 选型建议
  • 若需存储不重复的数据(如 ID、标签、去重数组),优先用Set;
  • 若需键值对映射(如配置表、缓存数据、字典),优先用Map;
  • 若键是引用类型(如对象),只能用Map;
  • 若只需简单的字符串键映射,且无需有序性,可考虑普通对象(但 Map 更灵活)。

五、性能优化与注意事项

  1. 性能对比
    • 插入 / 删除 / 查找操作:Set > Map > 数组 > 普通对象(数据量越大,优势越明显);
    • 遍历速度:Map > Set > 数组 > 普通对象(Map/Set 直接迭代,无需额外处理)。
  1. 注意事项
    • Set的forEach回调中,index 参数与 value 相同(设计特性,无需纠结);
    • Map的键是引用类型时,需保存同一引用才能修改 / 删除(避免隐式错误);
    • 避免用for...in遍历 Map/Set(不支持,需用for...of或forEach);
    • 序列化问题:JSON.stringify无法直接序列化 Map/Set,需手动转换为数组:

// Map序列化

const map = new Map([['a', 1]]);

const json = JSON.stringify([...map]); // "[[\"a\",1]]"

// Set序列化

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

const json = JSON.stringify([...set]); // "[1,2]"

六、总结

Set 和 Map 作为 ES6 的核心数据结构,解决了数组和普通对象的诸多痛点:Set 提供高效的不重复集合管理,Map 提供灵活的键值对映射。掌握它们的特性、API 和适用场景,能让你的代码更简洁、高效、易维护 —— 在数据去重、缓存管理、字典映射等场景中,它们往往是比数组和对象更优的选择。

建议在实际开发中多尝试用 Set/Map 替代传统数据结构,感受其带来的开发效率提升~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 2:22:17

55、Linux系统技术指南:从基础到高级配置与管理

Linux系统技术指南:从基础到高级配置与管理 1. 守护进程与数据管理 守护进程在系统后台持续运行,为系统提供各种服务。网络守护进程负责网络相关的服务,如网络连接、数据传输等。其相关内容涵盖从基础概述到具体的网络守护进程详细介绍,涵盖范围在32 - 34页。在数据管理方…

作者头像 李华
网站建设 2026/6/11 16:14:54

python+selenium自动化测试框架详解

本文整理归纳以往的工作中用到的东西,现汇总成基础测试框架提供分享。框架采用python3 selenium3 PO yaml ddt unittest等技术编写成基础测试框架,能适应日常测试工作需要。1、使用Page Object模式将页面定位和业务操作分开,分离测试对象…

作者头像 李华
网站建设 2026/6/10 16:50:55

21、线程安全函数与信号处理详解

线程安全函数与信号处理详解 1. 线程安全函数概述 在多线程编程中,线程安全是一个至关重要的概念。虽然 ANSI C 和 POSIX 1003.1 - 1990 在设计时并未考虑线程,但它们定义的大多数函数可以在不改变外部接口的情况下实现线程安全。例如, malloc 和 free 函数为了支持线…

作者头像 李华
网站建设 2026/6/14 5:03:58

23、线程同步:屏障与读写锁的实现与应用

线程同步:屏障与读写锁的实现与应用 在多线程编程中,同步机制是确保程序正确执行的关键。本文将深入探讨基于互斥锁(mutex)和条件变量(condition variable)构建的两种常见同步机制:屏障(barrier)和读写锁(read/write lock)。通过详细的代码示例和解释,帮助你更好地…

作者头像 李华