JavaScript 中的 Map、WeakMap、Set 详解

JavaScript 中的 Map、WeakMap、Set 详解

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

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提供了更强大的数据结构处理能力,根据具体场景选择合适的类型可以写出更高效、更安全的代码。

相关推荐
超哥--6 小时前
B站视频内容智能分析系统(九):React 前端与管理面板
前端·react.js·前端框架
Cutecat_9 小时前
视频字幕处理工具横向:提取模式 vs 编辑模式,该如何选择
android·前端·ios·语音识别
qq_4221525710 小时前
PDF 加水印工具怎么选?2026 年文档版权保护方案对比
前端·pdf·github
kyriewen10 小时前
手写 Promise.all、race、any:不到 30 行代码,解决并发异步的所有姿势
前端·javascript·面试
brucelee18611 小时前
OpenClaw 浏览器控制(Chrome MCP)完整教程
前端·chrome
ct97811 小时前
React 状态管理方案深度对比
开发语言·前端·react
胡志辉的博客11 小时前
深入浅出理解浏览器事件循环:从一道输出题讲到 Chrome 源码
前端·javascript·chrome·chromium·event loop
代码不加糖11 小时前
js中不会冒泡的事件有哪些?
前端·javascript·vue.js
懂懂tty12 小时前
Vue2与Vue3之间API差异
前端·javascript·vue.js
AI焦点12 小时前
跨越协议鸿沟:Tool Use状态机从Anthropic到OpenAI兼容体系的适配要点
前端·人工智能