JavaScript 提供了四种主要的集合类型:SetMapWeakSetWeakMap。这些集合类型在不同的场景中具有各自独特的优势和使用方式。本文将详细介绍这四种集合类型,通过代码示例展示其使用方法和特点。

Set:独一无二的集合

Set 的创建和基本操作

Set 是一个集合,它的所有元素都是唯一的。我们可以使用 Set 来存储不重复的值。以下是一些基本操作:

  1. // 创建一个新的 Set
  2. const mySet = new Set();
  3. // 添加元素
  4. mySet.add(1);
  5. mySet.add(2);
  6. mySet.add(2); // 重复的值不会被添加
  7. console.log(mySet); // 输出: Set { 1, 2 }
  8. // 检查是否存在某个元素
  9. console.log(mySet.has(1)); // 输出: true
  10. console.log(mySet.has(3)); // 输出: false
  11. // 删除元素
  12. mySet.delete(1);
  13. console.log(mySet); // 输出: Set { 2 }
  14. // 清空 Set
  15. mySet.clear();
  16. console.log(mySet); // 输出: Set {}

Set 的遍历

可以使用 for...of 循环或 forEach 方法遍历 Set 中的元素。

  1. const set = new Set([1, 2, 3]);
  2. // 使用 for...of 循环
  3. for (let item of set) {
  4. console.log(item); // 输出: 1 2 3
  5. }
  6. // 使用 forEach 方法
  7. set.forEach(item => {
  8. console.log(item); // 输出: 1 2 3
  9. });

Set 的常见应用场景

  • 数组去重:利用 Set 的唯一性特性,可以很方便地对数组进行去重。
  1. const numbers = [1, 2, 2, 3, 4, 4, 5];
  2. const uniqueNumbers = [...new Set(numbers)];
  3. console.log(uniqueNumbers); // 输出: [1, 2, 3, 4, 5]
  • 交集、并集和差集
  1. const setA = new Set([1, 2, 3]);
  2. const setB = new Set([3, 4, 5]);
  3. // 交集
  4. const intersection = new Set([...setA].filter(x => setB.has(x)));
  5. console.log(intersection); // 输出: Set { 3 }
  6. // 并集
  7. const union = new Set([...setA, ...setB]);
  8. console.log(union); // 输出: Set { 1, 2, 3, 4, 5 }
  9. // 差集
  10. const difference = new Set([...setA].filter(x => !setB.has(x)));
  11. console.log(difference); // 输出: Set { 1, 2 }

Map:键值对的集合

Map 的创建和基本操作

Map 是一个键值对的集合,其中键和值都可以是任意类型。以下是一些基本操作:

  1. // 创建一个新的 Map
  2. const myMap = new Map();
  3. // 添加键值对
  4. myMap.set('name', 'Alice');
  5. myMap.set('age', 25);
  6. console.log(myMap); // 输出: Map { 'name' => 'Alice', 'age' => 25 }
  7. // 获取值
  8. console.log(myMap.get('name')); // 输出: Alice
  9. console.log(myMap.get('age')); // 输出: 25
  10. // 检查是否存在某个键
  11. console.log(myMap.has('name')); // 输出: true
  12. console.log(myMap.has('address')); // 输出: false
  13. // 删除键值对
  14. myMap.delete('age');
  15. console.log(myMap); // 输出: Map { 'name' => 'Alice' }
  16. // 清空 Map
  17. myMap.clear();
  18. console.log(myMap); // 输出: Map {}

Map 的遍历

可以使用 for...of 循环遍历 Map 的键值对,或使用 forEach 方法。

  1. const map = new Map([
  2. ['name', 'Bob'],
  3. ['age', 30]
  4. ]);
  5. // 使用 for...of 循环
  6. for (let [key, value] of map) {
  7. console.log(`${key}: ${value}`); // 输出: name: Bob age: 30
  8. }
  9. // 使用 forEach 方法
  10. map.forEach((value, key) => {
  11. console.log(`${key}: ${value}`); // 输出: name: Bob age: 30
  12. });

Map 的常见应用场景

  • 对象键的扩展Map 允许使用任何类型的键,包括对象,而普通对象的键只能是字符串或符号。
  1. const objKey = { id: 1 };
  2. const myMap = new Map();
  3. myMap.set(objKey, 'Object Value');
  4. console.log(myMap.get(objKey)); // 输出: Object Value
  • 计数器:统计元素出现的次数。
  1. const items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
  2. const countMap = new Map();
  3. items.forEach(item => {
  4. countMap.set(item, (countMap.get(item) || 0) + 1);
  5. });
  6. console.log(countMap); // 输出: Map { 'apple' => 3, 'banana' => 2, 'orange' => 1 }

WeakSet:弱引用的集合

WeakSet 的创建和基本操作

WeakSet 是一个集合,它的所有元素必须是对象,且对其成员是弱引用。弱引用意味着如果没有其他引用指向某个对象,该对象会被垃圾回收机制回收。

  1. // 创建一个新的 WeakSet
  2. const weakSet = new WeakSet();
  3. let obj1 = { name: 'John' };
  4. let obj2 = { name: 'Jane' };
  5. // 添加对象
  6. weakSet.add(obj1);
  7. weakSet.add(obj2);
  8. console.log(weakSet.has(obj1)); // 输出: true
  9. // 删除对象
  10. weakSet.delete(obj1);
  11. console.log(weakSet.has(obj1)); // 输出: false
  12. // 对象被垃圾回收
  13. obj2 = null;
  14. console.log(weakSet.has(obj2)); // 输出: false

WeakSet 的特点

  • 只能包含对象WeakSet 的元素必须是对象,不能是原始值。
  • 弱引用WeakSet 对其元素是弱引用,不会阻止垃圾回收。

WeakSet 的常见应用场景

  • 存储临时对象WeakSet 适合存储仅在短期内需要使用的对象,避免内存泄漏。
  1. const visitedNodes = new WeakSet();
  2. function markNode(node) {
  3. visitedNodes.add(node);
  4. console.log('Node visited');
  5. }
  6. const node1 = { id: 1 };
  7. markNode(node1);
  8. console.log(visitedNodes.has(node1)); // 输出: true
  9. node1 = null; // node1 会被垃圾回收

WeakMap:弱引用的键值对集合

WeakMap 的创建和基本操作

WeakMap 是一个键值对的集合,其中键必须是对象,且对键是弱引用。

  1. // 创建一个新的 WeakMap
  2. const weakMap = new WeakMap();
  3. let obj1 = { name: 'Alice' };
  4. let obj2 = { name: 'Bob' };
  5. // 添加键值对
  6. weakMap.set(obj1, 'Engineer');
  7. weakMap.set(obj2, 'Designer');
  8. console.log(weakMap.get(obj1)); // 输出: Engineer
  9. // 删除键值对
  10. weakMap.delete(obj1);
  11. console.log(weakMap.has(obj1)); // 输出: false
  12. // 对象被垃圾回收
  13. obj2 = null;
  14. console.log(weakMap.has(obj2)); // 输出: false

WeakMap 的特点

  • 键必须是对象WeakMap 的键必须是对象,不能是原始值。
  • 弱引用WeakMap 对其键是弱引用,不会阻止垃圾回收。

WeakMap 的常见应用场景

  • 存储关联数据WeakMap 适合存储与对象关联的数据,避免内存泄漏。
  1. const metaData = new WeakMap();
  2. function setMetaData(obj, data) {
  3. metaData.set(obj, data);
  4. }
  5. function getMetaData(obj) {
  6. return metaData.get(obj);
  7. }
  8. const user = { name: 'John' };
  9. setMetaData(user, { age: 30 });
  10. console.log(getMetaData(user)); // 输出: { age: 30 }
  11. user = null; // user 对象会被垃圾回收,metaData 也会自动清除关联数据

集合的比较

特性 Set Map WeakSet WeakMap
存储的内容 唯一的值 键值对 对象 键值对
键的类型 值本身即为键 任意类型 对象 对象
值的类型 任意类型 任意类型 任意类型
检查元素存在性 has 方法 has 方法 has 方法 has 方法
添加元素或键值对 add 方法 set 方法 add 方法 set 方法
删除元素或键值对 delete 方法 delete 方法 delete 方法 delete 方法
获取元素或键值对 get 方法 get 方法
遍历方法 forEachfor...of forEachfor...of
弱引用

深度总结

JavaScript 中的 SetMapWeakSetWeakMap 为开发者提供了丰富的集合类型,适用于不同的场景。SetMap 提供了强引用的集合,适合存储需要频繁访问和操作的数据。WeakSetWeakMap 提供了弱引用的集合,适合存储临时数据和避免内存泄漏。

通过深入理解和熟练使用这些集合类型,你可以编写更加高效和可维护的代码,并更好地处理复杂的数据结构和算法。在实际开发中,根据具体需求选择合适的集合类型,能够极大地提升代码的性能和可维护性。因此,掌握这些集合类型是每个 JavaScript 开发者的必备技能。