带键集合
映射
Map 对象
一个 Map
对象是一个简单的键值映射,可以按插入顺序迭代其元素。
以下代码展示了使用 Map
的一些基本操作。有关更多示例和完整的 API,请参阅 Map
参考页面。您可以使用 for...of
循环来返回每次迭代的 [key, value]
数组。
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
对象和 Map 的比较
传统上,对象 用于将字符串映射到值。对象允许您将键设置为值,检索这些值,删除键以及检测是否在键处存储了内容。但是,Map
对象具有一些使其成为更好映射的优势。
Object
的键是 字符串 或 符号,而对于Map
,它们可以是任何值。- 您可以轻松获取
Map
的size
,而对于Object
,您必须手动跟踪大小。 - 地图的迭代是元素的插入顺序。
Object
有一个原型,因此映射中有一些默认键。(这可以通过使用map = Object.create(null)
来绕过。)
这三个技巧可以帮助您决定是使用 Map
还是 Object
- 当键在运行时之前未知时,以及当所有键都是相同类型且所有值都是相同类型时,请使用地图而不是对象。
- 如果需要将原始值存储为键,请使用地图,因为对象将每个键视为字符串,无论它是数字值、布尔值还是任何其他原始值。
- 当存在对单个元素进行操作的逻辑时,请使用对象。
WeakMap 对象
一个 WeakMap
是一个键值对集合,其键必须是对象或 未注册的符号,其值为任何任意 JavaScript 类型,并且不会对其键创建强引用。也就是说,对象作为 WeakMap
中键的存在不会阻止该对象被垃圾收集。一旦用作键的对象被收集,它在任何 WeakMap
中的相应值也会成为垃圾收集的候选者——只要它们没有在其他地方被强烈引用。唯一可以作为 WeakMap
键使用的原始类型是符号——更具体地说,是 未注册的符号——因为未注册的符号保证是唯一的,并且不能重新创建。
WeakMap
API 本质上与 Map
API 相同。但是,WeakMap
不允许观察其键的存活性,这就是它不允许枚举的原因。因此,没有方法可以获取 WeakMap
中键的列表。如果有,该列表将取决于垃圾收集的状态,从而引入不确定性。
有关更多信息和示例代码,请参阅 WeakMap
参考页面上的“为什么使用 WeakMap?”。
WeakMap
对象的一种用例是为对象存储私有数据,或隐藏实现细节。以下示例来自 Nick Fitzgerald 的博客文章 “使用 ECMAScript 6 WeakMaps 隐藏实现细节”。私有数据和方法属于对象内部,并存储在 privates
对象中,该对象是一个 WeakMap
。在实例和原型上公开的一切都是公开的;其他一切都是从外部世界无法访问的,因为 privates
没有从模块中导出。
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 对象
Set
对象是唯一值的集合。您可以按插入顺序迭代其元素。Set
中的值只能出现一次;它在 Set
的集合中是唯一的。
以下代码展示了使用 Set
的一些基本操作。有关更多示例和完整的 API,请参阅 Set
参考页面。
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"
在数组和 Set 之间转换
您可以使用 Array.from
或 扩展语法 从 Set 创建一个 Array
。此外,Set
构造函数接受一个 Array
来进行反向转换。
注意:Set
对象存储唯一值——因此,从数组转换时会删除任何重复元素!
Array.from(mySet);
[...mySet2];
mySet2 = new Set([1, 2, 3, 4]);
数组和 Set 的比较
传统上,在许多情况下,一组元素都存储在 JavaScript 的数组中。但是,Set
对象具有一些优势
- 按值删除数组元素 (
arr.splice(arr.indexOf(val), 1)
) 速度非常慢。 Set
对象允许您按值删除元素。对于数组,您必须根据元素的索引进行splice
。- 值
NaN
在数组中无法使用indexOf
找到。 Set
对象存储唯一值。您不必手动跟踪重复项。
WeakSet 对象
Map 和 Set 的键值相等性
Map
对象的键相等性和 Set
对象的值相等性都是基于 SameValueZero 算法
- 相等性类似于恒等比较运算符
===
。 -0
和+0
被认为是相等的。NaN
被认为与其自身相等(与===
相反)。