WeakMap 实践

169 阅读3分钟

WeakMap 是 JavaScript 提供的一种特殊的 Map 结构,主要用于存储弱引用的键值对。相较于 MapWeakMap 具有以下特点:

  • 键(key)只能是对象(而不能是基本类型,如字符串、数字)。
  • 当对象不再被引用时,WeakMap 里的键值对会自动被垃圾回收(GC)
  • 无法手动遍历 WeakMap,因为它的设计目标是让 GC 负责清理,而不是手动管理。

本文将通过一些实际案例,来展示 WeakMap 在前端开发中的应用场景。


1. WeakMap 的基本使用

let wm = new WeakMap();
let obj = { name: "Jack" };

wm.set(obj, "some data"); // 存入 WeakMap
console.log(wm.get(obj)); // "some data"

obj = null; // 删除 obj 的引用
// 这里 obj 没有其他引用,GC 可能会清除 obj,WeakMap 也会自动删除它

obj = null 之后,由于 obj 不再被引用,JavaScript 引擎的垃圾回收机制(GC)会自动回收该对象,同时 WeakMap 也会自动移除对应的键值对。


2. 使用 WeakMap 存储 DOM 相关数据

在前端开发中,某些数据只需要在 DOM 元素存在时存储,一旦元素被删除,就可以自动清除数据,避免内存泄漏。WeakMap 在这方面非常有用。

let wm = new WeakMap();
let element = document.getElementById("btn");

wm.set(element, "clicked");

element.addEventListener("click", () => {
    console.log(wm.get(element)); // "clicked"
});

element.remove(); // 移除 DOM 元素,GC 可能会自动回收,WeakMap 也会删除该键

为什么用 WeakMap

  • 避免内存泄漏:当 element 被移除后,GC 会自动回收,WeakMap 也会自动删除对应的数据。
  • 更安全的数据存储:数据不会被外部意外访问或修改。

3. 使用 WeakMap 进行私有属性封装

JavaScript 本身没有真正的私有属性,但可以使用 WeakMap 来实现。

const privateData = new WeakMap();

class Person {
    constructor(name, age) {
        privateData.set(this, { age });
        this.name = name;
    }

    getAge() {
        return privateData.get(this).age;
    }
}

const user = new Person("Alice", 30);
console.log(user.getAge()); // 30
console.log(user.age); // undefined,外部无法访问

为什么 WeakMap 可以用于私有属性?

  • 外部无法直接访问 WeakMap 存储的数据,只能通过类内部的方法访问。
  • 对象销毁后,私有数据也会自动删除,不会造成内存泄漏。

4. WeakMap 与普通 Map 的对比

特性MapWeakMap
键类型任意值(对象、字符串、数字)只能是对象
是否弱引用否,键值对会一直存在是,键无引用时会被 GC 回收
是否可遍历可以keys()forEach不可以,无遍历方法
适用场景需要长期存储数据短生命周期对象,如 DOM 绑定、私有数据

5. WeakMap 适合哪些场景?

✅ 适合:

  • 存储与对象关联的临时数据(如 DOM 元素的状态)。
  • 模拟私有变量,避免数据泄露。
  • 避免内存泄漏,对象销毁后数据会自动清理。

❌ 不适合:

  • 需要遍历所有键值对的场景WeakMap 不能遍历)。
  • 存储基本类型作为键(必须是对象)。

6. 结语

WeakMap 在 JavaScript 中虽然使用场景有限,但在防止内存泄漏、封装私有数据等方面提供了独特的优势。合理使用 WeakMap,可以让我们的代码更加安全、高效,尤其是在管理短生命周期对象时。