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