Set 与 Map 深度解析:区别、特性与应用场景,弱引用版本对比:WeakSet 与 WeakMap

Set 与 Map 深度解析:区别、特性与应用场景

一、核心定义

数据类型 存储内容 键/值要求 重复性规则
Set 唯一值的集合 只有值(无键) 值不能重复
Map 键值对的集合 键值任意类型(包括对象引用) 键不能重复

简单对比

  • Set:类似数组,但值唯一 [1, 2, 3]
  • Map:类似对象,但键可以是对象 { [obj]: "data" }

二、关键特性对比

特性 Set Map
初始化方式 new Set([1, 2, 3]) new Map([[k1,v1], [k2,v2]])
元素唯一性判断 值严格相等(===,但 NaN=NaN 键严格相等(===,但 NaN=NaN
元素访问 无索引,只能遍历或查存在 通过键访问:map.get(key)
顺序性 插入顺序保留 插入顺序保留
常用方法 add(), delete(), has() set(), get(), has()
大小获取 set.size map.size

三、核心方法详解

Set 操作示例

arduino 复制代码
JavaScript
const set = new Set();
set.add("apple");          // 添加值
set.add("banana");
console.log(set.size);     // 2
console.log(set.has("apple")); // true
set.delete("banana");      // 删除
set.clear();               // 清空

Map 操作示例

c 复制代码
JavaScript
const map = new Map();
const keyObj = { id: 1 };

map.set(keyObj, "data");     // 键为对象
map.set(123, "数字键");      // 键为数字
console.log(map.get(keyObj)); // "data"
map.delete(123);             // 删除键

四、特殊行为

  1. 重复值处理

    • Set 添加重复值自动忽略:

      csharp 复制代码
      JavaScript
      const set = new Set();
      set.add(1).add(1); // 最终只有 1 个元素
    • Map 重复键会覆盖旧值:

      c 复制代码
      JavaScript
      map.set("key", "v1");
      map.set("key", "v2"); // 值变为 v2
  2. NaN 的特殊相等

    arduino 复制代码
    JavaScript
    const set = new Set();
    set.add(NaN).add(NaN); // 只保留 1 个 NaN
    
    const map = new Map();
    map.set(NaN, "test");
    console.log(map.get(NaN)); // "test"(NaN 可作为键)

五、与弱引用版本对比:WeakSet 与 WeakMap

特性 WeakSet WeakMap 与普通版本区别
键要求 只接受对象作为值 只接受对象作为键 ✅ 键/值必须是对象引用
可遍历性 ❌ 不可遍历 ❌ 不可遍历 ✅ 无 sizekeys() 等方法
垃圾回收 元素无引用时自动回收 键对象无引用时自动回收 ✅ 防止内存泄漏
应用场景 临时对象跟踪 对象关联元数据

典型场景

kotlin 复制代码
JavaScript
// WeakMap 存储私有数据
const privateData = new WeakMap();

class Person {
  constructor(name) {
    privateData.set(this, { name }); // this 作键
  }
  getName() {
    return privateData.get(this).name;
  }
}

六、应用场景指南

场景描述 推荐数据结构 原因
存储唯一值(如用户ID) Set 自动去重,高效判断存在性
需要保留插入顺序的键值对 Map 比普通对象更可靠的顺序保证
键需为非字符串(如对象/函数) Map 普通对象键会自动转字符串
临时缓存对象(防内存泄漏) WeakSet/WeakMap 自动回收无引用的对象
为对象关联私有数据 WeakMap 键为对象本身,对象销毁时数据自动清除
交集/并集运算(如好友关系) Set 通过 union(), intersection() 等方法实现高效集合运算

七、性能关键点

  1. 查找效率

    • Set.has(value)Map.has(key) 的时间复杂度为 O(1) (哈希表实现),远快于数组的 includes()(O(n))
  2. 与数组转换

    sql 复制代码
    JavaScript
    // Set → Array
    const arr = [...set]; 
    // Array → Set (去重)
    const set = new Set(arr);
  3. 遍历优化

    arduino 复制代码
    JavaScript
    // Set 遍历
    for (const value of set) { ... }
    // Map 遍历
    for (const [key, value] of map) { ... }

总结

  • Set:处理唯一值集合,替代数组去重,高效值存在性检查
  • Map:键值对存储的升级版,支持任意类型键,保留插入顺序
  • WeakSet/WeakMap:专为对象设计的弱引用容器,防止内存泄漏
  • 性能优先 :高频查找用 Set/Map,数组遍历改用 for...of 或传统 for

优先选择 Set/Map 的场景:

  1. 需要维护插入顺序
  2. 键为非字符串
  3. 高频存在性检查
  4. 避免内存泄漏(用 Weak 版本)
相关推荐
无奈何杨7 分钟前
CoolGuard风控中新增移动距离和移动速度指标
前端·后端
恋猫de小郭15 分钟前
Google I/O Extended :2025 Flutter 的现状与未来
android·前端·flutter
江城开朗的豌豆19 分钟前
Vue-router方法大全:让页面跳转随心所欲!
前端·javascript·vue.js
程序员爱钓鱼28 分钟前
Go语言泛型-泛型约束与实践
前端·后端·go
前端小巷子30 分钟前
web从输入网址到页面加载完成
前端·面试·浏览器
江城开朗的豌豆31 分钟前
Vue路由动态生成秘籍:让你的链接'活'起来!
前端·javascript·vue.js
晓得迷路了31 分钟前
栗子前端技术周刊第 88 期 - Apache ECharts 6.0 beta、Deno 2.4、Astro 5.11...
前端·javascript·echarts
江城开朗的豌豆37 分钟前
在写vue公用组件的时候,怎么提高可配置性
前端·javascript·vue.js
江城开朗的豌豆37 分钟前
Vue路由跳转的N种姿势,总有一种适合你!
前端·javascript·vue.js
江城开朗的豌豆38 分钟前
Vue路由玩法大揭秘:三种路由模式你Pick谁?
前端·javascript·vue.js