--- title: 带键的集合 slug: Web/JavaScript/Guide/Keyed_collections tags: - Guide - JavaScript - Map - set - 集合 translation_of: Web/JavaScript/Guide/Keyed_collections ---
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}

这一章介绍由key值标记的数据容器;Map 和 Set 对象承载的数据元素可以按照插入时的顺序被迭代遍历。

映射

Map对象

ECMAScript 2015 引入了一个新的数据结构来将一个值映射到另一个值。一个{{jsxref("Map")}}对象就是一个简单的键值对映射集合,可以按照数据插入时的顺序遍历所有的元素。

下面的代码演示了使用Map进行的一些基本操作。请参考{{jsxref("Map")}}以获取更多的样例和完整的 API。你可以使用{{jsxref("Statements/for...of","for...of")}}循环来得到所有的[key, value]

var sayings = new Map();
sayings.set('dog', 'woof');
sayings.set('cat', 'meow');
sayings.set('elephant', 'toot');
sayings.size; // 3
sayings.get('fox'); // undefined
sayings.has('bird'); // false
sayings.delete('dog');
sayings.has('dog'); // false

for (var [key, value] of sayings) {
  console.log(key + ' goes ' + value);
}
// "cat goes meow"
// "elephant goes toot"

sayings.clear();
sayings.size; // 0

ObjectMap的比较

一般地,{{jsxref("Object", "objects", "", 1)}}会被用于将字符串类型映射到数值。Object允许设置键值对、根据键获取值、删除键、检测某个键是否存在。而Map具有更多的优势。

这三条提示可以帮你决定用Map还是Object

WeakMap对象

{{jsxref("WeakMap")}}对象也是键值对的集合。它的键必须是对象类型,值可以是任意类型。它的键被弱保持,也就是说,当其键所指对象没有其他地方引用的时候,它会被GC回收掉。WeakMap提供的接口与Map相同。

Map对象不同的是,WeakMap的键是不可枚举的。不提供列出其键的方法。列表是否存在取决于垃圾回收器的状态,是不可预知的。

可以在"Why WeakMap?"{{jsxref("WeakMap")}}查看更多信息和示例。

WeakMap对象的一个用例是存储一个对象的私有数据或隐藏实施细节。Nick Fitzgerald 的博文"Hiding Implementation Details with ECMAScript 6 WeakMaps"提供了一个例子。对象内部的私有数据和方法被存储在WeakMap类型的privates变量中。所有暴露出的原型和情况都是公开的,而其他内容都是外界不可访问的,因为模块并未导出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对象

{{jsxref("Set")}}对象是一组值的集合,这些值是不重复的,可以按照添加顺序来遍历。

这里演示了Set的基本操作,更多示例和完整API可以参考{{jsxref("Set")}}。

var mySet = new Set();
mySet.add(1);
mySet.add("some text");
mySet.add("foo");

mySet.has(1); // true
mySet.delete("foo");
mySet.size; // 2

for (let item of mySet) console.log(item);
// 1
// "some text"

数组和集合的转换

可以使用{{jsxref("Array.from")}}或展开操作符来完成集合到数组的转换。同样,Set的构造器接受数组作为参数,可以完成从ArraySet的转换。需要重申的是,Set对象中的值不重复,所以数组转换为集合时,所有重复值将会被删除。

Array.from(mySet);
[...mySet2];

mySet2 = new Set([1,2,3,4]);

ArraySet的对比

一般情况下,在JavaScript中使用数组来存储一组元素,而新的集合对象有这些优势:

WeakSet对象

{{jsxref("WeakSet")}}对象是一组对象的集合。WeakSet中的对象不重复且不可枚举。

与{{jsxref("Set")}}对象的主要区别有:

WeakSet的用例很有限,比如使用DOM元素作为键来追踪它们而不必担心内存泄漏。

Map的键和Set的值的等值判断

Map的键和Set的值的等值判断都基于same-value-zero algorithm

{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}