es6 集合
本文研究了四个新的ES6集合及其提供的好处。
大多数主要的编程语言都有几种类型的数据收集。 Python具有列表,元组和字典。 Java具有列表,集合,映射,队列。 Ruby具有哈希和数组。 到目前为止,JavaScript仅具有数组。 对象和数组是JavaScript的主力军。 ES6引入了四个新的数据结构,它们将为语言增加功能和表现力: Map
, Set
, WeakSet
和WeakMap
。
搜索JavaScript HashMap
HashMap,字典和散列是多种编程语言存储键/值对的几种方式,并且这些数据结构已针对快速检索进行了优化。
在ES5中,JavaScript对象(它们只是具有键和值的属性的任意集合)可以模拟哈希,但是将对象用作哈希有一些不利之处 。
缺点1:密钥在ES5中必须为字符串
JavaScript对象属性键必须是字符串,这限制了它们用作各种数据类型的键/值对的集合的能力。 当然,您可以将其他数据类型强制/字符串化为字符串,但这会增加额外的工作。
缺点2:对象不是固有可迭代的
对象并非设计为用作集合,因此,没有有效的方法来确定对象具有多少个属性。 (例如,参见Object.keys是slow )。 遍历对象的属性时,还将获得其原型属性。 您可以将iterable
属性添加到所有对象,但并非所有对象都应用作集合。 您可以使用for … in
循环和hasOwnProperty()
方法,但这只是一种解决方法。 当您遍历对象的属性时,不必按插入属性的顺序来检索属性。
缺点3:内置方法冲突带来的挑战
对象具有内置方法,如constructor
, toString
和valueOf
。 如果将其中之一添加为属性,则可能导致冲突。 您可以使用Object.create(null)
创建一个裸对象(它不继承自object.prototype
),但是同样,这只是一种解决方法。
ES6包括新的集合数据类型,因此不再需要使用对象并避免它们的缺点。
使用ES6地图集
Map
是我们要研究的第一个数据结构/集合。 映射是任何类型的键和值的集合。 创建新地图,添加/删除值,循环键/值并有效确定其大小非常容易。 以下是关键方法:
创建地图并使用常用方法
const map = new Map(); // Create a new Map
map.set('hobby', 'cycling'); // Sets a key value pair
const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // New Object
const normalfoods = {}; // New Object
map.set(normalfoods, foods); // Sets two objects as key value pair
for (const [key, value] of map) {
console.log(`${key} = ${value}`); // hobby = cycling [object Object] = [object Object]
}
map.forEach((value, key) => {
console.log(`${key} = ${value}`);
}, map); // hobby = cycling [object Object] = [object Object]
map.clear(); // Clears key value pairs
console.log(map.size === 0); // True
使用集合集合
集是不包含重复项的值的有序列表。 使用键可以访问集,而不是像数组那样被索引。 Java , Ruby , Python和许多其他语言已经存在集合。 ES6集与其他语言中的集之间的区别是,顺序在ES6中很重要(在许多其他语言中不那么重要)。 这是关键的Set方法:
const planetsOrderFromSun = new Set();
planetsOrderFromSun.add('Mercury');
planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // Chainable Method
console.log(planetsOrderFromSun.has('Earth')); // True
planetsOrderFromSun.delete('Mars');
console.log(planetsOrderFromSun.has('Mars')); // False
for (const x of planetsOrderFromSun) {
console.log(x); // Same order in as out - Mercury Venus Earth
}
console.log(planetsOrderFromSun.size); // 3
planetsOrderFromSun.add('Venus'); // Trying to add a duplicate
console.log(planetsOrderFromSun.size); // Still 3, Did not add the duplicate
planetsOrderFromSun.clear();
console.log(planetsOrderFromSun.size); // 0
弱集合,内存和垃圾集合
JavaScript垃圾回收是一种内存管理方式,通过该方式,不再引用的对象将自动删除,并回收其资源。
对对象的Map
和Set
的引用被严格保留,并且不允许进行垃圾回收。 如果地图/集引用不再需要的大对象(例如已经从DOM中删除的DOM元素),则这可能会变得昂贵。
为了解决这个问题,ES6还引入了两个新的弱集合,称为WeakMap
和WeakSet
。 这些ES6集合“弱”是因为它们允许不再需要从内存中清除的对象。
弱地图
WeakMap是我们要介绍的新ES6集合中的第三个。 WeakMaps
与普通Maps
相似,尽管方法更少,并且在垃圾回收方面存在上述差异。
const aboutAuthor = new WeakMap(); // Create New WeakMap
const currentAge = {}; // key must be an object
const currentCity = {}; // keys must be an object
aboutAuthor.set(currentAge, 30); // Set Key Values
aboutAuthor.set(currentCity, 'Denver'); // Key Values can be of different data types
console.log(aboutAuthor.has(currentCity)); // Test if WeakMap has a key
aboutAuthor.delete(currentAge); // Delete a key
用例
WeakMaps 有几种流行的用例 。 它们可用于使对象的私有数据保持私有,也可用于跟踪DOM节点/对象。
私人数据用例
以下示例来自JavaScript专家Nicholas C. Zakas :
var Person = (function() {
var privateData = new WeakMap();
function Person(name) {
privateData.set(this, { name: name });
}
Person.prototype.getName = function() {
return privateData.get(this).name;
};
return Person;
}());
<source type="image/webp"><source><img src="https://s2.51cto.com/images/blog/202406/21233056_66759cb0a681f54001.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=" alt="">
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。 原价$ 11.95 您的完全免费
免费获得这本书
在这里使用WeakMap
简化保持对象数据私有的过程。 可以引用Person
对象,但是如果没有特定的Person
实例,则不允许访问privateDataWeakMap
。
DOM节点用例
Google Polymer项目在名为PositionWalker的一段代码中使用WeakMaps
。
PositionWalker跟踪DOM子树中作为当前节点的位置以及该节点内的偏移量。
WeakMap用于跟踪DOM节点的编辑,删除和更改:
_makeClone() {
this._containerClone = this.container.cloneNode(true);
this._cloneToNodes = new WeakMap();
this._nodesToClones = new WeakMap();
...
let n = this.container;
let c = this._containerClone;
// find the currentNode's clone
while (n !== null) {
if (n === this.currentNode) {
this._currentNodeClone = c;
}
this._cloneToNodes.set(c, n);
this._nodesToClones.set(n, c);
n = iterator.nextNode();
c = cloneIterator.nextNode();
}
}
弱集
WeakSets
是Set集合,当不再需要它们引用的对象时,可以对其元素进行垃圾回收。 WeakSets
不允许迭代。 他们的用例非常有限 (至少目前是这样)。 大多数早期采用者说, WeakSets
可用于标记对象而无需对其进行突变 。 ES6-Features.org有一个示例,可以从WeakSet中添加和删除元素 ,以便跟踪对象是否已被标记:
let isMarked = new WeakSet()
let attachedData = new WeakMap()
export class Node {
constructor (id) { this.id = id }
mark () { isMarked.add(this) }
unmark () { isMarked.delete(this) }
marked () { return isMarked.has(this) }
set data (data) { attachedData.set(this, data) }
get data () { return attachedData.get(this) }
}
let foo = new Node("foo")
JSON.stringify(foo) === '{"id":"foo"}'
foo.mark()
foo.data = "bar"
foo.data === "bar"
JSON.stringify(foo) === '{"id":"foo"}'
isMarked.has(foo) === true
attachedData.has(foo) === true
foo = null /* remove only reference to foo */
attachedData.has(foo) === false
isMarked.has(foo) === false
地图所有东西? 记录与ES6集合
映射和集合是键/值对的漂亮的ES6新集合。 也就是说,JavaScript对象在许多情况下仍可以用作集合。 除非情况需要,否则无需切换到新的ES6集合。
MDN有一个不错的问题列表,用于确定何时使用对象或键控集合:
- 通常在运行时才知道密钥,您是否需要动态查找它们?
- 所有值都具有相同的类型,并且可以互换使用吗?
- 您是否需要不是字符串的键?
- 是经常添加或删除键值对吗?
- 您是否有任意数量(轻松更改)的键值对?
- 集合是否迭代?
新的ES6集合产生了更有用JavaScript
JavaScript集合以前非常有限,但是ES6已对此进行了补救。 这些新的ES6集合将增加语言的功能和灵活性,并简化采用它们JavaScript开发人员的任务。
本文是Microsoft技术传播者和DevelopIntelligence的Web开发系列文章的一部分,内容涉及实用JavaScript学习,开源项目以及互操作性最佳实践,包括Microsoft Edge浏览器和新的EdgeHTML呈现引擎 。 DevelopIntelligence通过appendTo提供JavaScript培训和React培训课程,它们是前端博客和课程站点。
我们鼓励您使用dev.microsoftedge.com上的免费工具(包括EdgeHTML问题跟踪器 )在包括EdgeEdge 问题跟踪器在内的所有浏览器和设备上进行测试,包括Microsoft Edge(Windows 10的默认浏览器) ,您可以在其中报告或搜索EdgeHTML问题,例如站点问题。渲染或符合标准。 另外, 请访问Edge博客以获取最新信息,并获得Microsoft开发人员和专家的最新信息。
翻译自: https://www.sitepoint.com/es6-collections-map-set-weakmap-weakset/
es6 集合