JavaScript 中的 Map、WeakMap、Set 详解

JavaScript 中的 Map、WeakMap、Set 详解

在 JavaScript 中,Map、WeakMap、Set 是用于存储数据集合的特殊对象类型,它们各有特点和应用场景。下面我将详细解释它们的用法并提供具体案例。

1. Map(映射)

Map 是一种键值对集合,其中键可以是任意类型(对象、原始值等)。

基本用法

javascript 复制代码
// 创建 Map
const userMap = new Map();

// 添加键值对
userMap.set('name', 'Alice');
userMap.set(1, 'ID');
userMap.set({ role: 'admin' }, '权限对象');

// 获取值
console.log(userMap.get('name')); // 'Alice'
console.log(userMap.get(1));      // 'ID'

// 检查键是否存在
console.log(userMap.has('name')); // true

// 删除键值对
userMap.delete(1);

// 获取大小
console.log(userMap.size); // 2

// 遍历 Map
userMap.forEach((value, key) => {
  console.log(`${key}: ${value}`);
});

// 清空 Map
userMap.clear();

使用对象作为键

javascript 复制代码
const user1 = { id: 1 };
const user2 = { id: 2 };

const preferences = new Map();
preferences.set(user1, { theme: 'dark', lang: 'en' });
preferences.set(user2, { theme: 'light', lang: 'fr' });

console.log(preferences.get(user1).theme); // 'dark'

与普通对象的区别

特性 Map 普通对象
键的类型 任意类型 String/Symbol
顺序 插入顺序 无序
大小 .size 属性 手动计算
性能 频繁增删时更优 相对较慢
默认键 无 有原型链属性

2. WeakMap(弱映射)

WeakMap 与 Map 类似,但有重要区别:

  • 键必须是对象
  • 键是弱引用(不阻止垃圾回收)
  • 不可遍历(没有迭代方法)

基本用法

javascript 复制代码
const weakMap = new WeakMap();

let obj1 = { id: 1 };
let obj2 = { id: 2 };

// 设置键值对
weakMap.set(obj1, '私有数据1');
weakMap.set(obj2, '私有数据2');

// 获取值
console.log(weakMap.get(obj1)); // '私有数据1'

// 删除
weakMap.delete(obj1);

// 检查存在
console.log(weakMap.has(obj2)); // true

典型应用:私有成员

javascript 复制代码
const privateData = new WeakMap();

class User {
  constructor(name) {
    // 每个实例的私有数据存储在WeakMap中
    privateData.set(this, { name });
  }
  
  getName() {
    return privateData.get(this).name;
  }
}

const user = new User('Alice');
console.log(user.getName()); // 'Alice'
console.log(privateData.get(user)); // { name: 'Alice' }
console.log(user.name); // undefined(真正私有)

WeakMap 特点

  • 当键对象被垃圾回收时,对应的值也会自动清除
  • 没有 size 属性
  • 不能使用 forEach() 或 for...of 遍历
  • 不支持清空整个 WeakMap

3. Set(集合)

Set 是唯一值的集合,每个值只能出现一次。

基本用法

javascript 复制代码
const uniqueNumbers = new Set();

// 添加值
uniqueNumbers.add(1);
uniqueNumbers.add(2);
uniqueNumbers.add(2); // 重复值会被忽略
uniqueNumbers.add('text');
uniqueNumbers.add({ id: 1 });

// 检查存在
console.log(uniqueNumbers.has(1)); // true

// 获取大小
console.log(uniqueNumbers.size); // 4

// 删除值
uniqueNumbers.delete('text');

// 遍历 Set
uniqueNumbers.forEach(value => {
  console.log(value);
});

// 转换为数组
const numbersArray = [...uniqueNumbers];

// 清空
uniqueNumbers.clear();

常见应用场景

1. 数组去重

javascript 复制代码
const duplicates = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(duplicates)];
console.log(unique); // [1, 2, 3, 4, 5]

2. 求交集/并集/差集

javascript 复制代码
const setA = new Set([1, 2, 3]);
const setB = new Set([2, 3, 4]);

// 并集
const union = new Set([...setA, ...setB]);

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

// 差集 (A - B)
const difference = new Set([...setA].filter(x => !setB.has(x)));

console.log([...union]);        // [1, 2, 3, 4]
console.log([...intersection]); // [2, 3]
console.log([...difference]);   // [1]

3. 跟踪唯一对象

javascript 复制代码
const visitedNodes = new Set();

function traverse(node) {
  if (visitedNodes.has(node)) return;
  
  visitedNodes.add(node);
  // 处理节点...
  for (let child of node.children) {
    traverse(child);
  }
}

对比总结表

特性 Map WeakMap Set
键类型 任意类型 必须是对象 存储值(无键)
值类型 任意类型 任意类型 唯一值
可迭代 是 否 是
大小 .size 属性 不可获取 .size 属性
垃圾回收 强引用(阻止回收) 弱引用(不阻止回收) 强引用(阻止回收)
遍历方法 forEach, for...of, keys 无 forEach, for...of
主要用途 键值对存储(键可为对象) 对象关联元数据/私有成员 唯一值集合/数学集合操作
性能 增删查 O(1) 增删查 O(1) 增删查 O(1)

什么时候使用?

  • 使用 Map 当需要:

    • 键值对集合且键不是字符串
    • 需要保持插入顺序
    • 需要频繁添加/删除键值对
  • 使用 WeakMap 当需要:

    • 关联对象与元数据而不影响垃圾回收
    • 实现真正的私有属性
    • 存储对象特定的元信息
  • 使用 Set 当需要:

    • 存储唯一值
    • 快速检查值是否存在
    • 执行集合操作(并集、交集等)

这些集合类型为JavaScript提供了更强大的数据结构处理能力,根据具体场景选择合适的类型可以写出更高效、更安全的代码。

相关推荐
console.log('npc')9 分钟前
[特殊字符] AI Agent 工作台前端实战教程 · 新手入门指南
前端·人工智能
gCode Teacher 格码致知13 分钟前
前端教学2:ul标签的应用场合与经典案例
前端
const_qiu32 分钟前
第 2.5 章 2.5.6:前端登录、Token 无感续签与路由守卫
java·前端·人工智能·状态模式
用户831348593069842 分钟前
Vue3 事件:常用用法与开发高频坑点
前端·javascript·vue.js
weixin_4462608542 分钟前
ReAct‑Evolve:基于轨迹反馈的ReAct智能体自主提示演化系统
前端·react.js·前端框架
其实防守也摸鱼1 小时前
存储管理:页面置换算法学习任务(测验题要求给出置换页面顺序,缺页次数,缺页率)
android·前端·数据库·学习·oracle·自动化
怒放的生命19911 小时前
前端项目 Docker 打包实操指南
前端·docker·容器
tedcloud1231 小时前
Docker Compose 部署 Immich:手机照片自动备份与常见故障排查
运维·前端·docker·容器·智能手机·开源·流程图
时间的情敌1 小时前
《WebGIS 前端的成长路线,三维可视化工程师需要掌握什么》
前端·状态模式
漫步人生走在路上1 小时前
用小语种SEO突破外贸B2B天花板:法语、德语市场的实测数据
开发语言·前端·javascript·人工智能·搜索引擎·ecmascript