在JavaScript中,Set和Map的性能有什么区别?

简介: 在JavaScript中,Set和Map的性能有什么区别?

在 JavaScript 中,SetMap 的底层实现均基于哈希表(Hash Table),因此在大多数操作上性能表现相近,但由于设计目的不同,仍存在细微差异。以下是两者性能的详细对比及适用场景分析:

一、核心操作的时间复杂度

操作 Set Map 说明
添加元素 add(value) set(key, value) 均为 O(1) 平均时间复杂度
删除元素 delete(value) delete(key) 均为 O(1) 平均时间复杂度
检查存在性 has(value) has(key) 均为 O(1) 平均时间复杂度
获取元素数量 size size 均为 O(1) 直接返回属性值
遍历所有元素 values() entries() 均为 O(n) 需遍历所有元素
清空集合 clear() clear() 均为 O(1) 重置内部状态

二、性能差异的具体场景

1. 添加与查找操作

  • Set:适用于存储单一值的集合,添加和查找时无需处理键值对映射,略快于 Map。

    const set = new Set();
    set.add(1); // 直接存储值,无需键
    console.log(set.has(1)); // O(1),查找速度快
    
  • Map:需维护键值对映射,操作略复杂,但仍保持 O(1) 时间复杂度。

    const map = new Map();
    map.set("key", 1); // 需处理键值对
    console.log(map.get("key")); // O(1),但多一步键的哈希计算
    

2. 键的类型对性能的影响

  • Set:仅存储值,无需计算键的哈希值,性能稍优。
  • Map:键可以是任意类型(包括对象),需为每个键计算哈希值,开销略高。
    const objKey = {
         };
    map.set(objKey, "value"); // 对象键需额外计算哈希值
    

3. 大数据量下的内存占用

  • Set:仅存储值,内存占用相对较小。
  • Map:需存储键值对,内存占用约为 Set 的两倍(相同数量的元素)。

三、性能测试示例

以下代码对比了 Set 和 Map 在大数据量下的插入和查找性能:

// 测试环境:Chrome 浏览器,100万条数据
const size = 1000000;

// 测试 Set
const set = new Set();
console.time("Set add");
for (let i = 0; i < size; i++) {
   
  set.add(i);
}
console.timeEnd("Set add"); // 约 20-30ms

console.time("Set has");
for (let i = 0; i < size; i++) {
   
  set.has(i);
}
console.timeEnd("Set has"); // 约 15-25ms

// 测试 Map
const map = new Map();
console.time("Map set");
for (let i = 0; i < size; i++) {
   
  map.set(i, i);
}
console.timeEnd("Map set"); // 约 30-40ms

console.time("Map get");
for (let i = 0; i < size; i++) {
   
  map.get(i);
}
console.timeEnd("Map get"); // 约 25-35ms

结果说明

  • 插入操作:Map 比 Set 慢约 30%,因需处理键值对。
  • 查找操作:Map 比 Set 慢约 20%,因需额外处理键的哈希值。

四、性能优化建议

  1. 优先使用 Set 存储单一值集合
    若只需存储唯一值且无需键值映射,Set 的性能和内存效率均优于 Map。

  2. 仅在需要键值映射时使用 Map
    Map 的优势在于支持任意类型的键,且遍历时保持插入顺序,适合缓存、映射关系等场景。

  3. 避免频繁删除和重新添加元素
    哈希表在删除元素后可能不会立即释放内存,频繁删除添加可能导致内存碎片。

  4. 大数据量下的遍历优化
    若需频繁遍历集合,Set 和 Map 的性能相近,但需注意 Map 返回的是键值对,处理开销略高。

五、总结:如何根据性能选择?

场景 推荐使用 Set 推荐使用 Map
存储唯一值集合 ✅ 性能和内存效率更高 ❌ 内存占用多,操作略慢
快速检查元素存在性 ✅ 略快于 Map ❌ 键值对处理开销略高
需要键值映射关系 ❌ 不支持键值对 ✅ 设计初衷即为此场景
键的类型为对象或函数 ❌ 无法通过对象查找 ✅ 支持任意类型的键
大数据量下的频繁插入/删除 ✅ 略优 ❌ 略慢(但仍为 O(1))

理解两者性能差异后,可根据具体业务需求选择合适的数据结构,在保证功能正确性的同时优化性能。

目录
相关文章
|
12天前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
61 1
|
3月前
|
存储 缓存 JavaScript
Set和Map有什么区别?
Set和Map有什么区别?
294 1
|
4月前
|
存储 JavaScript 前端开发
Set中的add()方法和数组的push()方法有什么区别?
Set中的add()方法和数组的push()方法有什么区别?
320 122
|
4月前
|
存储 JavaScript 前端开发
for...of循环在遍历Set和Map时的注意事项有哪些?
for...of循环在遍历Set和Map时的注意事项有哪些?
275 121
|
7月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
194 2
|
4月前
|
存储 C++ 容器
unordered_set、unordered_multiset、unordered_map、unordered_multimap的介绍及使用
unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。在unordered_set中,元素的值同时也是唯一地标识它的key。在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低。它的迭代器至少是前向迭代器。前向迭代器的特性。
197 0
|
4月前
|
编译器 C++ 容器
用一棵红黑树同时封装出map和set
再完成上面的代码后,我们的底层代码已经完成了,这时候已经是一个底层STL的红黑树了,已经已符合库里面的要求了,这时候我们是需要给他穿上对应的“衣服”,比如穿上set的“衣服”,那么这个穿上set的“衣服”,那么他就符合库里面set的要求了,同样map一样,这时候我们就需要实现set与map了。因此,上层容器map需要向底层红黑树提供一个仿函数,用于获取T当中的键值Key,这样一来,当底层红黑树当中需要比较两个结点的键值时,就可以通过这个仿函数来获取T当中的键值了。我们就可以使用仿函数了。
56 0
|
4月前
|
存储 编译器 容器
set、map、multiset、multimap的介绍及使用以及区别,注意事项
set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。set默认是升序的,但是其内部默认不是按照大于比较,而是按照小于比较。set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。
213 0
|
8月前
|
编译器 容器
哈希表模拟封装unordered_map和unordered_set
哈希表模拟封装unordered_map和unordered_set
|
8月前
|
编译器 测试技术 计算机视觉
红黑树模拟封装map和set
红黑树模拟封装map和set

热门文章

最新文章