Set、Map、WeakSet 和 WeakMap

在 JavaScript 中,SetMapWeakSetWeakMap 是四种重要的集合类型,它们各自有独特的特性和适用场景。理解它们的区别对于编写高效、安全的代码至关重要。

一、Set(集合)

1. 基本特性

  • 唯一值:存储唯一的值,重复值会被自动过滤
  • 无序性:元素没有特定顺序,不能通过索引访问
  • 可迭代:支持 for...offorEach 等迭代方法

2. 常用方法

  • add(value):添加值,返回 Set 本身
  • delete(value):删除值,返回布尔值表示是否成功
  • has(value):检查值是否存在
  • clear():清空集合
  • size:返回元素数量

3. 示例

const set = new Set();
set.add(1);
set.add(2);
set.add(2); // 重复值,会被忽略

console.log(set.size); // 2
console.log(set.has(2)); // true

set.delete(1);
console.log(set.has(1)); // false

// 迭代
for (const value of set) {
  console.log(value); // 2
}

4. 应用场景

  • 数组去重:[...new Set([1, 2, 2, 3])]
  • 快速查找:has 方法效率高于 Array.includes
  • 存储不重复的值集合

二、Map(映射)

1. 基本特性

  • 键值对:存储键值对,键和值可以是任意类型
  • 有序性:按照插入顺序迭代元素
  • 可迭代:支持 for...offorEach 等迭代方法

2. 常用方法

  • set(key, value):设置键值对,返回 Map 本身
  • get(key):获取键对应的值,不存在时返回 undefined
  • delete(key):删除键值对,返回布尔值表示是否成功
  • has(key):检查键是否存在
  • clear():清空映射
  • size:返回键值对数量

3. 示例

const map = new Map();
const objKey = { id: 1 };

map.set(objKey, 'value associated with objKey');
map.set('stringKey', 42);

console.log(map.get(objKey)); // 'value associated with objKey'
console.log(map.has('stringKey')); // true
console.log(map.size); // 2

// 迭代
for (const [key, value] of map) {
  console.log(key, value);
}

4. 与 Object 的区别

特性 Map Object
键的类型 任意类型 字符串或 Symbol
顺序性 保持插入顺序 不保证顺序(ES6+ 字符串键按插入顺序)
大小 通过 size 属性获取 需要手动计算
默认值 无默认键 原型链上的键可能导致冲突
迭代 直接支持 需要先获取键数组

5. 应用场景

  • 复杂键的映射:例如使用对象作为键
  • 频繁增删键值对的场景
  • 需要有序遍历的场景

三、WeakSet(弱集合)

1. 基本特性

  • 只能存储对象:存储的对象必须是引用类型
  • 弱引用:对对象的引用是弱引用,不阻止对象被垃圾回收
  • 不可迭代:不支持 for...ofsize 等属性和方法
  • 方法有限:只有 adddeletehas 三个方法

2. 示例

const weakSet = new WeakSet();
const obj = {};

weakSet.add(obj);
console.log(weakSet.has(obj)); // true

// 无法遍历 WeakSet
// 以下代码会报错:TypeError: weakSet is not iterable
// for (const item of weakSet) { ... }

3. 弱引用特性

let obj = {};
const weakSet = new WeakSet();
weakSet.add(obj);

console.log(weakSet.has(obj)); // true

// 释放对象引用
obj = null;

// 垃圾回收后,WeakSet 中该对象会被自动移除

4. 应用场景

  • 存储 DOM 元素引用,避免内存泄漏
  • 跟踪对象是否存在,但不阻止其被回收
  • 实现私有状态(通过 WeakSet 存储对象标识)

四、WeakMap(弱映射)

1. 基本特性

  • 键只能是对象:值可以是任意类型
  • 弱引用:键对对象的引用是弱引用,不阻止对象被垃圾回收
  • 不可迭代:不支持 for...ofsize 等属性和方法
  • 方法有限:只有 setgetdeletehas 四个方法

2. 示例

const weakMap = new WeakMap();
const objKey = {};

weakMap.set(objKey, 'secret value');
console.log(weakMap.get(objKey)); // 'secret value'

// 无法遍历 WeakMap
// 以下代码会报错:TypeError: weakMap is not iterable
// for (const [key, value] of weakMap) { ... }

3. 弱引用特性

let obj = {};
const weakMap = new WeakMap();
weakMap.set(obj, 'data');

console.log(weakMap.has(obj)); // true

// 释放对象引用
obj = null;

// 垃圾回收后,WeakMap 中该键值对会被自动移除

4. 应用场景

  • 存储对象的私有数据(如 React 的 ref 实现)
  • 缓存计算结果,避免内存泄漏
  • DOM 元素关联元数据(元素被移除时自动清理)

五、四者对比表格

特性 Set Map WeakSet WeakMap
存储内容 键值对 对象 键值对(键为对象)
键的类型 任意类型 任意类型 必须是对象 必须是对象
重复值处理 自动过滤重复值 键唯一,重复会覆盖值 不支持重复对象 键唯一,重复会覆盖值
弱引用
可迭代性
大小属性 size size
典型应用场景 去重、成员检测 复杂键映射、有序存储 临时对象跟踪 私有数据、DOM 关联数据

六、面试高频问题

  1. Set 和数组的区别是什么?
    答:Set 存储唯一值,不支持索引访问,插入和查找效率更高;数组允许重复值,支持索引访问和更多操作方法。

  2. Map 和 Object 的主要区别有哪些?
    答:Map 的键可以是任意类型,保持插入顺序,有明确的 size 属性,且默认没有原型链上的键;Object 的键只能是字符串或 Symbol,不保证顺序,需要手动计算大小。

  3. WeakSet 和 WeakMap 的弱引用特性有什么用?
    答:弱引用不会阻止对象被垃圾回收,适合存储临时关联数据,避免内存泄漏。例如,当 DOM 元素被移除时,WeakMap 中关联的元数据会自动被清理。

  4. 什么情况下应该使用 WeakMap?
    答:适合以下场景:

    • 存储对象的私有数据
    • 缓存计算结果,且不希望阻止对象被回收
    • 关联 DOM 元素的元数据
  5. 如何实现一个对象的私有属性?
    答:可以使用 WeakMap 实现:

    const privateData = new WeakMap();
    
    class MyClass {
      constructor() {
        privateData.set(this, {
          secret: 'private value'
        });
      }
    
      getSecret() {
        return privateData.get(this).secret;
      }
    }
    

总结

  • Set:用于存储唯一值的集合,适合去重和成员检测
  • Map:用于键值对映射,支持任意类型的键,保持插入顺序
  • WeakSet:存储对象的弱集合,不阻止对象被回收,不可迭代
  • WeakMap:以对象为键的弱映射,用于存储私有数据或临时关联

在选择使用哪种集合类型时,需要考虑数据类型、是否需要弱引用、是否需要迭代以及性能要求等因素。合理使用这些集合类型可以使代码更加高效、安全和易维护。

Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""