WeakMap

上一节我们讨论了 Map 是什么,以及它都有哪些供我们使用的方法。那么这一节我们来讲讲和它差不多的 WeakMap 究竟是什么东西。

WeakMap 官方描述

原文如下:

WeakMap objects are collections of key/value pairs where the keys are objects and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects it holds as keys. If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.
An implementation may impose an arbitrarily determined latency between the time a key/value pair of a WeakMap becomes inaccessible and the time when the key/value pair is removed from the WeakMap. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to observe a key of a WeakMap that does not require the observer to present the observed key.
WeakMap objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of key/value pairs in the collection. The data structure used in this WeakMap objects specification are only intended to describe the required observable semantics of WeakMap objects. It is not intended to be a viable implementation model.

我们可以看出原文对它描述很细致也很详细,翻译如下:

WeakMap 对象是键/值对的集合,其中键是对象,值可以是任意的 ECMAScript 语言值。可以查询WeakMap 来查看它是否包含具有特定键的键/值对,但是它没有提供用于枚举其作为键的对象的机制。如果正在用作 WeakMap 键/值对的键的对象只能通过跟随从该 WeakMap 中开始的引用链访问,那么该键/值对是不可访问的,并且会自动从 WeakMap 中删除。 WeakMap 内置系统必须检测和删除这样的键/值对和任何相关的资源。
内置系统可以在 WeakMap 的键/值对变得不可访问的时间与从 WeakMap 中移除键/值对的时间之间施加任意确定的延迟。如果 ECMAScript 程序可观察到这种延迟,那么它将是可能影响程序执行的不确定性的来源。因此,ECMAScript 内置系统不能提供任何方法来观察 WeakMap 的键,不需要观察者呈现观察到的键。
WeakMap 对象必须使用哈希表或其他机制实现,平均来说,提供对集合中键/值对数量进行亚线性的访问时间。此 WeakMap 对象规范中使用的数据结构仅用于描述 WeakMap 对象所需的可观察语义。它不是一个可行的内置系统模型。

我们可以看到这段话很长,需要我们耐心的去阅读它。其中,最重要的是,WeakMap 的键只能是对象!也就是说,我们不可以使用字符串、数值、布尔值以及 Symbol 作为它的键,这样会抛出一个错误。我们只可以使用对象、数组等来作为它的键。如下所示:

// 错误
let map = new WeakMap();
map.set(1,'a');
console.log(map);
错误提示

从这张图我们就可以看出来,这是不行的。

// 正确
let map = new WeakMap();
let o1 = {};  // 或 []
map.set(o1,'a');
console.log(map);

结果如下图:

正确代码

当然了,我们也可以将对象传入进去。示例如下:

let map = new WeakMap();
let o1 = {1: 'a',2: 'b'};
map.set(o1,'name');
console.log(map);

输出结果:

输出结果

这样我们就完成了一个简单的对象映射。那么这又有什么用呢?

我们说 WeakMap 的存在意义就在于“垃圾回收”。简单来说,我们将对象放入到 WeakMap 中,这样就可以防止内存泄漏,会被 js 垃圾收集器带走。什么是垃圾收集器呢?还是一句话就能理解了:例如我们定义的函数,当它被使用后,那么他就会被当做垃圾收集走以清理内存的占用。

另外,我们注意到还有一句话:WeakMap 没有提供用于枚举其作为键的对象的机制

也就是说,WeakMap 是一个不可枚举的对象。换言之,它没有 entries()、keys() 以及 values() 三个类似的方法。另外,它也不拥有 clear() 这个方法。这点好理解,如果它的实例都能被清理掉,那么 WeakMap 也就没有了存在的意义。

也就是说,我们使用 WeakMap 创建的实例是“私有数据”


WeakMap 的创建

一般来说,WeakMap 的实例创建通常是以下两种方式:

  1. 通过属性键的命名方式。
  1. 在构造函数的环境中创建。

以下是一个示例,是通过第二种方式创建的实例。使用 _counter 和 _action 参数储存私有数据:

let _counter = new WeakMap();
let _action = new WeakMap();

class Countdown {
    constructor(counter, action) {
        _counter.set(this, counter);
        _action.set(this, action);
}

    dec() {
        let counter = _counter.get(this);
        if (counter < 1) return;
            counter--;
            _counter.set(this, counter);
        if (counter === 0) {
            _action.get(this)();
        }
    }
}

而第一种方式,我在前面已经写出了示例,所以这里就不着重介绍了。相信大家都会的。


WeakMap 原型方法

WeakMap 一共只有 4 个原型方法,与 Map 的方法一致。

(1)WeakMap.prototype.delete ( key )

概述:delete() 方法可以从一个 WeakMap 对象中删除指定的元素。

示例:

var wm = new WeakMap();
wm.set(window, "foo");

wm.delete(window); // 返回 true,表示删除成功。
wm.has(window); // 返回 false,因为 window 对象已经被删除了。

(2)WeakMap.prototype.get ( key )

概述:get() 方法返回 WeakMap 指定的元素。

示例:

var wm = new WeakMap();
wm.set(window, "foo");

wm.get(window); // 返回 "foo"
wm.get("baz"); // 返回 undefined

(3)WeakMap.prototype.has ( key )

概述: has() 方法根据 WeakMap 对象的元素中是否存在 key 返回一个布尔值。

示例:

var wm = new WeakMap();
wm.set(window, "foo");

wm.has(window);  // 返回 true
wm.has("baz");  // 返回 false

(4)WeakMap.prototype.set ( key )

概述:set() 方法根据指定的 key 和 value 在 WeakMap 对象中添加新/更新元素。

示例:

let map = new WeakMap();
let o1 = {1: 'a'};
map.set(o1,'name');  // 设置值
map.set(o1,'value');  // 更新值

总结

我们从本章看出 WeakMap 并没有多少知识点。重点中的重点在于它使用的场景是什么?这才是我们所需要和探索的领域。

你可能感兴趣的:(WeakMap)