JS中的 WeakSet 和 WeakMap

在JavaScript中,WeakSetWeakMap 是两个相对较少被提及但非常有用的集合类型。它们与我们熟悉的 MapSet 类似,但有一些独特的特性和用途。

一、从对象和 Map 开始

在深入探讨 WeakSetWeakMap 之前,我们先简单回顾一下 JavaScript 中的对象和 Map

对象

对象是 JavaScript 中最常用的数据结构之一。它是一个键值对的集合,键和值都可以是任意类型。例如:

javascript 复制代码
const algorithm = { site: "leetcode" };
console.log(algorithm.site); // leetcode

for (const key in algorithm) {
  console.log(key, algorithm[key]);
}

// site leetcode
delete algorithm.site;
console.log(algorithm.site); // undefined

对象的属性可以通过点符号(.)访问,也可以通过中括号([])访问。对象的属性可以通过 delete 关键字删除。

Map

Map 是一个更强大的集合类型,它允许键和值为任意类型。与对象不同,Map 的键是唯一的,且 Map 是可迭代的。例如:

javascript 复制代码
const map = new Map();
map.set('name', 'john');
map.set('phone', 'iPhone');
console.log(map.get('phone')); // iPhone
console.log(map.has('phone')); // true
console.log(map.size); // 2

for (const item of map) {
  console.dir(item);
}
// Array(2) ["name", "john"]
// Array(2) ["phone", "iPhone"]

Map 提供了许多有用的方法,如 setgethasdeleteclear

二、WeakMap

WeakMapMap 的一个变种,它与 Map 非常相似,但有一些关键的区别。

特性

  1. 键必须是对象WeakMap 的键必须是对象,不能是原始类型(如字符串、数字等)。例如:

    javascript 复制代码
    const John = { name: 'John' };
    const weakMap = new WeakMap();
    weakMap.set(John, 'student');
    // WeakMap {{...} => "student"}
    weakMap.set('john', 'student');
    // Uncaught TypeError: Invalid value used as weak map key
  2. 弱引用WeakMap 的键是弱引用的。这意味着如果一个对象只被 WeakMap 引用,而没有其他引用指向它,那么这个对象可能会被垃圾回收器回收。例如:

    javascript 复制代码
    let John = { major: "math" };
    const weakMap = new WeakMap();
    weakMap.set(John, 'student');
    John = null; // John 被垃圾回收
  3. 不可迭代WeakMap 不支持迭代方法,如 keysvaluesentries。因此,你无法直接遍历 WeakMap 中的键值对。

方法

WeakMap 提供了以下方法:

  • set(key, value):设置键值对。
  • get(key):获取键对应的值。
  • has(key):检查是否存在某个键。
  • delete(key):删除某个键。

使用场景

WeakMap 通常用于以下场景:

  1. 私有数据存储 :由于 WeakMap 的键是弱引用的,且不可迭代,它非常适合用于存储私有数据。例如,你可以为一个对象存储一些私有状态,而不用担心这些状态会泄漏到其他地方。

    javascript 复制代码
    const privateData = new WeakMap();
    const obj = { public: 'public' };
    privateData.set(obj, 'private');
    console.log(privateData.get(obj)); // private
  2. 缓存WeakMap 可以用于缓存对象的某些计算结果。由于键是弱引用的,当对象被垃圾回收时,对应的缓存也会自动清除。

    javascript 复制代码
    const cache = new WeakMap();
    const obj = { data: 'some data' };
    cache.set(obj, processData(obj.data));

三、WeakSet

WeakSetSet 的一个变种,它也具有一些独特的特性。

特性

  1. 成员必须是对象WeakSet 的成员必须是对象,不能是原始类型。例如:

    javascript 复制代码
    const John = { name: 'John' };
    const weakSet = new WeakSet();
    weakSet.add(John);
    // WeakSet {{...}}
    weakSet.add('john');
    // Uncaught TypeError: Invalid value used as weak set key
  2. 弱引用WeakSet 中的对象是弱引用的。如果一个对象只被 WeakSet 引用,而没有其他引用指向它,那么这个对象可能会被垃圾回收器回收。例如:

    javascript 复制代码
    let John = { major: "math" };
    const weakSet = new WeakSet();
    weakSet.add(John);
    John = null; // John 被垃圾回收
  3. 不可迭代WeakSet 不支持迭代方法,如 forEach。因此,你无法直接遍历 WeakSet 中的成员。

方法

WeakSet 提供了以下方法:

  • add(value):添加一个成员。
  • delete(value):删除一个成员。
  • has(value):检查是否包含某个成员。

使用场景

WeakSet 通常用于以下场景:

  1. 对象标记 :你可以使用 WeakSet 来标记某些对象,而不用担心这些对象会泄漏。例如,你可以标记某些对象为"已处理"或"已验证"。

    javascript 复制代码
    const processed = new WeakSet();
    const obj = { data: 'some data' };
    processed.add(obj);
    console.log(processed.has(obj)); // true
  2. 对象池WeakSet 可以用于管理对象池。当对象被垃圾回收时,它们会自动从 WeakSet 中移除,从而避免内存泄漏。

    javascript 复制代码
    const objectPool = new WeakSet();
    const obj = { data: 'some data' };
    objectPool.add(obj);

四、总结

WeakMapWeakSet 是 JavaScript 中非常有用的集合类型,它们提供了弱引用的特性,这使得它们在某些场景下非常有用。WeakMap 适用于存储私有数据和缓存,而 WeakSet 适用于对象标记和对象池管理。由于它们的弱引用特性,它们可以帮助我们避免内存泄漏,同时保持代码的简洁和高效。

相关推荐
烛阴21 分钟前
Date-fns教程:现代JavaScript日期处理从入门到精通
前端·javascript
全栈小528 分钟前
【前端】Vue3+elementui+ts,TypeScript Promise<string>转string错误解析,习惯性请出DeepSeek来解答
前端·elementui·typescript·vue3·同步异步
穗余37 分钟前
NodeJS全栈开发面试题讲解——P6安全与鉴权
前端·sql·xss
独行soc1 小时前
2025年渗透测试面试题总结-匿名[校招]高级安全工程师(代码审计安全评估)(题目+回答)
linux·安全·web安全·面试·职场和发展·渗透测试
小蜜蜂嗡嗡1 小时前
flutter项目迁移空安全
javascript·安全·flutter
穗余2 小时前
NodeJS全栈开发面试题讲解——P2Express / Nest 后端开发
前端·node.js
航Hang*2 小时前
WEBSTORM前端 —— 第3章:移动 Web —— 第4节:移动适配-VM
前端·笔记·edge·less·css3·html5·webstorm
江城开朗的豌豆2 小时前
JavaScript篇:a==0 && a==1 居然能成立?揭秘JS中的"魔法"比较
前端·javascript·面试
江城开朗的豌豆2 小时前
JavaScript篇:setTimeout遇上for循环:为什么总是输出5?如何正确输出0-4?
前端·javascript·面试
橘子味的冰淇淋~3 小时前
npm run build 报错:Some chunks are larger than 500 KB after minification
前端·npm·node.js