键控集合
本章介绍通过键索引的数据集合;Map
和 Set
对象包含可按插入顺序迭代的元素。
¥This chapter introduces collections of data which are indexed by a key; Map
and Set
objects contain elements which are iterable in the order of insertion.
映射
映射对象
¥Map object
Map
对象是一个简单的键/值映射,可以按插入顺序迭代其元素。
¥A Map
object is a simple key/value map and can iterate its elements in insertion order.
以下代码显示了 Map
的一些基本操作。另请参阅 Map
参考页以获取更多示例和完整的 API。你可以使用 for...of
循环为每次迭代返回 [key, value]
的数组。
¥The following code shows some basic operations with a Map
. See also the Map
reference page for more examples and the complete API. You can use a for...of
loop to return an array of [key, value]
for each iteration.
const sayings = new Map();
sayings.set("dog", "woof");
sayings.set("cat", "meow");
sayings.set("elephant", "toot");
sayings.size; // 3
sayings.get("dog"); // woof
sayings.get("fox"); // undefined
sayings.has("bird"); // false
sayings.delete("dog");
sayings.has("dog"); // false
for (const [key, value] of sayings) {
console.log(`${key} goes ${value}`);
}
// "cat goes meow"
// "elephant goes toot"
sayings.clear();
sayings.size; // 0
对象和映射的比较
¥Object and Map compared
传统上,objects 用于将字符串映射到值。对象允许你将键设置为值、检索这些值、删除键以及检测键中是否存储了某些内容。然而,Map
对象还有一些优点,使它们成为更好的地图。
¥Traditionally, objects have been used to map strings to values. Objects allow you to set keys to values, retrieve those values, delete keys, and detect whether something is stored at a key. Map
objects, however, have a few more advantages that make them better maps.
Object
的键是 strings 或 symbols,而Map
的键可以是任何值。- 你可以轻松获得
Map
的size
,而你必须手动跟踪Object
的尺寸。 - 映射的迭代按照元素的插入顺序进行。
Object
有原型,所以地图中有默认键。(这可以使用map = Object.create(null)
绕过。)
这三个提示可以帮助你决定是使用 Map
还是 Object
:
¥These three tips can help you to decide whether to use a Map
or an Object
:
- 当键在运行时之前未知,并且所有键都是相同类型并且所有值都是相同类型时,请在对象上使用映射。
- 如果需要将原始值存储为键,请使用映射,因为对象将每个键视为字符串,无论它是数字值、布尔值还是任何其他原始值。
- 当存在对单个元素进行操作的逻辑时,请使用对象。
弱映射对象
¥WeakMap object
WeakMap
是键/值对的集合,其键必须是对象或 非注册符号,具有任意 JavaScript 类型 的值,并且不会创建对其键的强引用。也就是说,对象作为 WeakMap
中的键的存在不会阻止该对象被垃圾收集。一旦用作键的对象被收集,它在任何 WeakMap
中的对应值也将成为垃圾收集的候选者 - 只要它们在其他地方没有被强烈引用。唯一可以用作 WeakMap
键的原始类型是符号(更具体地说,是 非注册符号),因为未注册的符号保证是唯一的并且无法重新创建。
¥A WeakMap
is a collection of key/value pairs whose keys must be objects or non-registered symbols, with values of any arbitrary JavaScript type, and which does not create strong references to its keys. That is, an object's presence as a key in a WeakMap
does not prevent the object from being garbage collected. Once an object used as a key has been collected, its corresponding values in any WeakMap
become candidates for garbage collection as well — as long as they aren't strongly referred to elsewhere. The only primitive type that can be used as a WeakMap
key is symbol — more specifically, non-registered symbols — because non-registered symbols are guaranteed to be unique and cannot be re-created.
WeakMap
API 本质上与 Map
API 相同。然而,WeakMap
不允许观察其键的活跃度,这就是它不允许枚举的原因。所以没有办法获取 WeakMap
中的键列表。如果有的话,该列表将取决于垃圾收集的状态,从而引入非确定性。
¥The WeakMap
API is essentially the same as the Map
API. However, a WeakMap
doesn't allow observing the liveness of its keys, which is why it doesn't allow enumeration. So there is no method to obtain a list of the keys in a WeakMap
. If there were, the list would depend on the state of garbage collection, introducing non-determinism.
有关更多信息和示例代码,另请参阅 WeakMap
参考页上的 "为什么是 WeakMap?"。
¥For more information and example code, see also "Why WeakMap?" on the WeakMap
reference page.
WeakMap
对象的一个用例是存储对象的私有数据,或隐藏实现细节。以下示例来自 Nick Fitzgerald 的博客文章 "使用 ECMAScript 6 WeakMap 隐藏实现细节"。私有数据和方法属于对象内部,存储在 privates
对象中,该对象是 WeakMap
。实例和原型上暴露的所有内容都是公开的;其他一切都无法从外界访问,因为 privates
未从模块导出。
¥One use case of WeakMap
objects is to store private data for an object, or to hide implementation details. The following example is from Nick Fitzgerald's blog post "Hiding Implementation Details with ECMAScript 6 WeakMaps". The private data and methods belong inside the object and are stored in the privates
object, which is a WeakMap
. Everything exposed on the instance and prototype is public; everything else is inaccessible from the outside world because privates
is not exported from the module.
const privates = new WeakMap();
function Public() {
const me = {
// Private data goes here
};
privates.set(this, me);
}
Public.prototype.method = function () {
const me = privates.get(this);
// Do stuff with private data in `me`
// …
};
module.exports = Public;
套
设置对象
¥Set object
Set
对象是唯一值的集合。你可以按插入顺序迭代其元素。Set
中的值只能出现一次;它在 Set
系列中是独一无二的。
¥Set
objects are collections of unique values. You can iterate its elements in insertion order. A value in a Set
may only occur once; it is unique in the Set
's collection.
以下代码显示了 Set
的一些基本操作。另请参阅 Set
参考页以获取更多示例和完整的 API。
¥The following code shows some basic operations with a Set
. See also the Set
reference page for more examples and the complete API.
const mySet = new Set();
mySet.add(1);
mySet.add("some text");
mySet.add("foo");
mySet.has(1); // true
mySet.delete("foo");
mySet.size; // 2
for (const item of mySet) {
console.log(item);
}
// 1
// "some text"
数组和集合之间的转换
¥Converting between Array and Set
你可以使用 Array.from
或 扩展语法 从集合中创建 Array
。此外,Set
构造函数接受 Array
以进行相反方向的转换。
¥You can create an Array
from a Set using Array.from
or the spread syntax. Also, the Set
constructor accepts an Array
to convert in the other direction.
注意:
Set
对象存储唯一值 - 因此转换时数组中的任何重复元素都会被删除!¥Note:
Set
objects store unique values—so any duplicate elements from an Array are deleted when converting!
Array.from(mySet);
[...mySet2];
mySet2 = new Set([1, 2, 3, 4]);
数组和集合比较
¥Array and Set compared
传统上,在很多情况下,JavaScript 中的一组元素都存储在数组中。然而,Set
对象有一些优点:
¥Traditionally, a set of elements has been stored in arrays in JavaScript in a lot of situations. The Set
object, however, has some advantages:
- 按值(
arr.splice(arr.indexOf(val), 1)
)删除数组元素非常慢。 Set
对象允许你按值删除元素。对于数组,你必须根据元素的索引进行splice
。- 在数组中找不到值
NaN
和indexOf
。 Set
对象存储唯一值。你不必手动跟踪重复项。
弱集对象
¥WeakSet object
WeakSet
对象是垃圾可回收值的集合,包括对象和 非注册符号。WeakSet
中的值只能出现一次。它在 WeakSet
系列中是独一无二的。
¥WeakSet
objects are collections of garbage-collectable values, including objects and non-registered symbols. A value in the WeakSet
may only occur once. It is unique in the WeakSet
's collection.
与 Set
对象的主要区别是:
¥The main differences to the Set
object are:
- 与
Sets
相比,WeakSets
仅是对象或符号的集合,而不是任何类型的任意值的集合。 WeakSet
很弱:对集合中对象的引用保持较弱。如果没有其他对存储在WeakSet
中的对象的引用,它们可以被垃圾收集。这也意味着集合中没有存储当前对象的列表。WeakSets
不可枚举。
WeakSet
对象的用例是有限的。它们不会泄漏内存,因此可以安全地使用 DOM 元素作为键并将其标记用于跟踪目的。
¥The use cases of WeakSet
objects are limited. They will not leak memory, so it can be safe to use DOM elements as a key and mark them for tracking purposes, for example.
Map 和 Set 的键和值相等
¥Key and value equality of Map and Set
Map
对象的键相等性和 Set
对象的值相等性均基于 SameValueZero 算法:
¥Both the key equality of Map
objects and the value equality of Set
objects are based on the SameValueZero algorithm:
- 相等的工作原理类似于恒等比较运算符
===
。 -0
和+0
被认为是相等的。NaN
被认为等于其自身(与===
相反)。