导读:本期聚焦于小伙伴创作的《JavaScript WeakMap是什么,它有什么特殊用途?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《JavaScript WeakMap是什么,它有什么特殊用途?》有用,将其分享出去将是对创作者最好的鼓励。

JavaScript中的WeakMap是ES6引入的一种新的集合类型,它和Map一样用于存储键值对,但拥有很多独有的特性。WeakMap的键必须是对象类型,并且这些键对对象的引用是弱引用,这一设计让它在某些场景下比Map更合适。

JavaScript WeakMap是什么,它有什么特殊用途?

WeakMap的基本定义与创建

WeakMap的构造函数接收一个可迭代对象作为参数,该可迭代对象的每个元素都应该是包含两个对象的数组,第一个元素是键,第二个元素是值。如果不需要初始化数据,也可以直接调用构造函数创建空WeakMap。

// 创建空WeakMap
const weakMap1 = new WeakMap();

// 创建带初始数据的WeakMap,键必须是对象
const key1 = { id: 1 };
const key2 = { id: 2 };
const weakMap2 = new WeakMap([
    [key1, 'value1'],
    [key2, 'value2']
]);

console.log(weakMap2.has(key1)); // 输出 true

WeakMap的核心特性

1. 键只能是对象

WeakMap的键不允许是原始类型,比如字符串、数字、布尔值等都不能作为WeakMap的键,尝试使用原始类型作为键会直接抛出类型错误。

const weakMap = new WeakMap();
// 以下代码会抛出TypeError
weakMap.set('stringKey', 'value'); 
weakMap.set(123, 'value');

2. 弱引用特性

WeakMap对键的引用是弱引用,这意味着如果没有其他变量引用这个键对象,那么即使该对象还在WeakMap中作为键存在,也会被垃圾回收机制回收。而Map对键的引用是强引用,只要键值对还在Map中,键对象就不会被回收。

let obj = { name: 'test' };
const weakMap = new WeakMap();
const map = new Map();

weakMap.set(obj, 'weakValue');
map.set(obj, 'mapValue');

// 移除obj的外部引用
obj = null;

// 此时obj对象没有外部强引用,WeakMap中的键引用是弱引用,所以obj会被垃圾回收
// 而Map中的键是强引用,obj不会被回收,可能导致内存泄漏

3. 不可枚举

WeakMap没有size属性,也不支持迭代方法,比如keys()、values()、entries()都不能使用,也无法用for...of遍历,这是因为弱引用的特性导致无法确定WeakMap中当前的键值对数量,枚举操作也不安全。

const weakMap = new WeakMap();
const key = {};
weakMap.set(key, 'value');

console.log(weakMap.size); // 输出 undefined,WeakMap没有size属性
// 以下代码会抛出TypeError,WeakMap不可枚举
for (const item of weakMap) {}

WeakMap与Map的差异对比

为了更清晰地理解WeakMap的特性,我们可以将它和普通Map做对比,具体差异如下:

对比项MapWeakMap
键的类型可以是任意类型,包括原始类型和对象只能是对象类型
引用类型强引用弱引用
是否可枚举是,支持size属性和迭代方法否,没有size属性,不支持迭代
内存管理键值对存在时,键不会被垃圾回收键无外部强引用时会被垃圾回收

WeakMap的特殊用途

1. 私有数据存储

在ES2022之前,JavaScript没有原生的私有属性语法,我们可以用WeakMap来存储对象的私有数据,因为WeakMap不可枚举,外部无法直接获取存储的内容,并且当对象被回收时,对应的私有数据也会被自动清理。

// 用WeakMap存储私有数据
const privateData = new WeakMap();

class User {
    constructor(name, age) {
        this.name = name; // 公共属性
        // 存储私有属性age
        privateData.set(this, { age: age });
    }

    getAge() {
        // 通过WeakMap获取私有属性
        return privateData.get(this).age;
    }
}

const user = new User('张三', 20);
console.log(user.name); // 输出 张三,公共属性可访问
console.log(user.getAge()); // 输出 20,通过方法获取私有属性
// 无法直接访问privateData中的内容,也无法枚举privateData获取所有私有数据

2. 避免内存泄漏的临时数据存储

当我们需要给对象关联一些临时数据,并且不希望这些关联数据阻止对象被垃圾回收时,WeakMap是很好的选择。比如给DOM元素关联一些状态数据,当DOM元素被移除时,对应的状态数据会自动被回收。

// 给DOM元素关联临时状态
const elementState = new WeakMap();

const button = document.querySelector('button');
// 给按钮关联点击次数状态
elementState.set(button, { clickCount: 0 });

button.addEventListener('click', () => {
    const state = elementState.get(button);
    state.clickCount++;
    console.log(`按钮点击次数:${state.clickCount}`);
});

// 当button元素被从DOM中移除,且没有其它变量引用时,button会被垃圾回收
// 对应的elementState中的键值对也会被自动清理,不会造成内存泄漏

3. 关联对象与元数据

在一些框架或库的开发中,经常需要给对象关联一些元数据,比如给组件实例关联配置信息、给函数关联缓存数据等,使用WeakMap可以避免手动管理这些元数据的清理工作。

// 给函数关联缓存数据
const funcCache = new WeakMap();

function expensiveFunc(obj) {
    if (funcCache.has(obj)) {
        // 如果已经有缓存,直接返回
        return funcCache.get(obj);
    }
    // 模拟耗时计算
    const result = Object.keys(obj).length * 2;
    // 存储缓存,键是obj对象
    funcCache.set(obj, result);
    return result;
}

const dataObj = { a: 1, b: 2 };
console.log(expensiveFunc(dataObj)); // 输出 4
console.log(expensiveFunc(dataObj)); // 输出 4,使用缓存结果

// 当dataObj没有外部引用时,缓存数据会自动被清理

WeakMap的常用方法

WeakMap只提供了四个实例方法,功能比较简单:

  • set(key, value):向WeakMap中添加键值对,键必须是对象,返回WeakMap本身,支持链式调用。
  • get(key):获取指定键对应的值,如果键不存在则返回undefined。
  • has(key):判断WeakMap中是否存在指定的键,返回布尔值。
  • delete(key):删除指定的键值对,成功删除返回true,否则返回false。
const weakMap = new WeakMap();
const key = {};

// set方法链式调用
weakMap.set(key, 'value1').set({ id: 2 }, 'value2');

console.log(weakMap.get(key)); // 输出 value1
console.log(weakMap.has(key)); // 输出 true

console.log(weakMap.delete(key)); // 输出 true
console.log(weakMap.has(key)); // 输出 false

使用WeakMap的注意事项

虽然WeakMap有很多优势,但使用时也有一些需要注意的点:

首先,不要试图去获取WeakMap中的所有键或者所有值,因为它本身不支持枚举操作,这也是弱引用特性决定的,枚举操作可能会获取到已经被垃圾回收一半的状态,导致不可预期的问题。

其次,如果需要存储原始类型作为键,或者需要遍历集合中的所有元素,那么应该选择普通的Map而不是WeakMap。WeakMap的设计初衷就是为了解决弱引用相关的场景,不适合所有键值对存储的需求。

最后,在Node.js环境中调试时,WeakMap的内容无法直接通过控制台查看,这也是因为它不可枚举的特性,需要结合具体的键对象才能获取对应的值。

JavaScriptWeakMap弱引用垃圾回收引用类型修改时间:2026-06-30 10:48:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。