Map 是一种新的集合类型,为这门语言带来了真正的键/ 值存储机 制。 Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。
使用 new 关键字和 Map 构造函数可以创建一个空映射。
// 使用嵌套数组初始化映射
const m1 = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3'],
]);
alert(m1.size); // 3 // 使用自定义迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function* () {
yield ['key1', 'val1'];
yield ['key2', 'val2'];
yield ['key3', 'val3'];
},
});
alert(m2.size); // 3
// 映射期待的键/ 值对,无论是否提供
const m3 = new Map([[]]);
alert(m3.has(undefined)); //true
alert(m3.get(undefined)); // undefined
初始化之后,可以使用 set() 方法再添加键/ 值对。另外,可以使用 get() 和 has() 进行查询,可 以通过 size 属性获取映射中的键/ 值对的数量,还可以使用 delete() 和 clear() 删除值。
const m = new Map();
alert(m.has('firstName')); // false
alert(m.get('firstName')); //undefined
alert(m.size); // 0
m.set('firstName', 'Matt').set('lastName', 'Frisbie');
alert(m.has('firstName')); // true
alert(m.get('firstName')); // Matt
alert(m.size); // 2
m.delete('firstName'); // 只删除这一个键/ 值对
alert(m.has('firstName')); // false
alert(m.has('lastName')); // true
alert(m.size); // 1 m.clear(); //清除这个映射实例中的所有键 / 值对;
alert(m.has('firstName')); // false
alert(m.has('lastName')); // false
alert(m.size); // 0
与 Object 类型的一个主要差异是, Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执 行迭代操作。 映射实例可以提供一个迭代器( Iterator ),能以插入顺序生成[key, value] 形式的数组。可以 通过 entries() 方法(或者 Symbol.iterator 属性,它引用 entries() )取得这个迭代器
const m = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3'],
]);
alert(m.entries === m[Symbol.iterator]); // true
for (let pair of m.entries()) {
alert(pair);
}
// [key1,val1] //
[key2, val2];
// [key3,val3]
for (let pair of m[Symbol.iterator]()) {
alert(pair);
} // [key1,val1] // [key2,val2]
// [key3,val3]
Object 和 Map 的工程级实现在不同浏览器间存在明显差异,但存储单个键/ 值对所占用的内存数量 都会随键的数量线性增加。批量添加或删除键/ 值对则取决于各浏览器对该类型内存分配的工程实现。 不同浏览器的情况不同,但给定固定大小的内存, Map 大约可以比 Object 多存储 50% 的键/ 值对。
Object 和 Map 中插入新键/ 值对的消耗大致相当,不过插入 Map 在所有浏览器中一般会稍微快 一点儿。对这两个类型来说,插入速度并不会随着键/ 值对数量而线性增加。如果代码涉及大量插入操 作,那么显然 Map 的性能更佳。
与插入不同,从大型 Object 和 Map 中查找键/ 值对的性能差异极小,但如果只包含少量键/ 值对, 则 Object 有时候速度更快。在把 Object 当成数组使用的情况下(比如使用连续整数作为属性),浏 览器引擎可以进行优化,在内存中使用更高效的布局。这对 Map 来说是不可能的。对这两个类型而言, 查找速度不会随着键/ 值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选 择 Object 更好一些。
使用 delete 删除 Object 属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此, 出现了一些伪删除对象属性的操作,包括把属性值设置为 undefined 或 null 。但很多时候,这都是一 种讨厌的或不适宜的折中。而对大多数浏览器引擎来说, Map 的 delete() 操作都比插入和查找更快。 如果代码涉及大量删除操作,那么毫无疑问应该选择 Map 。
ECMAScript 6 新增的" 弱映射" ( WeakMap )是一种新的集合类型,为这门语言带来了增强的键/ 值对存储机制。 WeakMap 是 Map 的" 兄弟" 类型,其 API 也是 Map 的子集。 WeakMap 中的"weak" (弱), 描述的是 JavaScript 垃圾回收程序对待" 弱映射" 中键的方式。
可以使用 new 关键字实例化一个空的:
WeakMap : const wm = new WeakMap();
WeakMap 中"weak" 表示弱映射的键是" 弱弱地拿着" 的。意思就是,这些键不属于正式的引用, 不会阻止垃圾回收。但要注意的是,弱映射中值的引用可不是" 弱弱地拿着" 的。只要键存在,键/ 值 对就会存在于映射中,并被当作对值的引用,因此就不会被当作垃圾回收。
set() 方法初始化了一个新对象并将它用作一个字符串的键。因为没有指向这个对象的其它引用, 所以当这行代码执行完成后,这个对象键就会被当作垃圾回收。然后,这个键/ 值对就从弱映射中消失 了,使其成为一个空映射。
因为 WeakMap 中的键/ 值对任何时候都可能被销毁,所以没必要提供迭代其键/ 值对的能力。当然, 也用不着像 clear() 这样一次性销毁所有键/ 值的方法。 WeakMap 确实没有这个方法。因为不可能迭代, 所以也不可能在不知道对象引用的情况下从弱映射中取得值。即便代码可以访问 WeakMap 实例,也没 办法看到其中的内容。
ECMAScript 6 新增的 Set 是一种新集合类型,为这门语言带来集合数据结构。 Set 在很多方面都 像是加强的 Map ,这是因为它们的大多数 API 和行为都是共有的。
const s = new Set();
alert(s.has('Matt')); //false
alert(s.size); // 0
s.add('Matt').add('Frisbee');
alert(s.has('Matt')); // true
alert(s.size); // 2
s.delete('Matt');
alert(s.has('Matt')); // false
alert(s.has('Frisbee')); // true
alert(s.size); // 1
s.clear(); // 销毁集合实例中的所有值
alert(s.has('Matt')); // false
alert(s.has('Frisbee')); // false
alert(s.size); // 0
与 Map 类似, Set 可以包含任何 JavaScript 数据类型作为值。集合也使用 SameValueZero 操作 ( ECMAScript 内部定义,无法在语言中使用),基本上相当于使用严格对象相等的标准来检查值的匹 配性。
const s = new Set();
const functionVal = function () {};
const symbolVal = Symbol();
const objectVal = new Object();
s.add(functionVal);
s.add(symbolVal);
s.add(objectVal);
alert(s.has(functionVal)); // true
alert(s.has(symbolVal)); // true
alert(s.has(objectVal)); // true //SameValueZero 检查意味着独立的实例不会冲突
alert(s.has(function () {}));
// false
Set 会维护值插入时的顺序,因此支持按顺序迭代。
集合实例可以提供一个迭代器( Iterator ),能以插入顺序生成集合内容。可以通过 values() 方 法及其别名方法 keys() (或者 Symbol.iterator 属性,它引用 values() )取得这个迭代器。
const s = new Set(['val1', 'val2', 'val3']);
alert(s.values === s[Symbol.iterator]); // true
alert(s.keys === s[Symbol.iterator]); // true
for (let value of s.values()) {
alert(value);
}
// val1
// val2
// val3
for (let value of s[Symbol.iterator]()) {
alert(value);
}
// val1;
// val2
// val3
ECMAScript 6 新增的" 弱集合" ( WeakSet )是一种新的集合类型,为这门语言带来了集合数据结 构。 WeakSet 是 Set 的" 兄弟" 类型,其 API 也是 Set 的子集。 WeakSet 中的"weak" (弱),描述的 是 JavaScript 垃圾回收程序对待" 弱集合" 中值的方式。