本文探讨了四个新的ES6集合以及它们带来的好处。
大多数主要的编程语言都有几种类型的数据集合。Python有列表、元组和字典。Java有列表、集合、映射、队列。Ruby有哈希和数组。到目前为止,JavaScript只有数组。对象和数组是JavaScript的得力助手。ES6引入了四个新的数据结构,它们将增强语言的强大功能和表达能力:Map、Set、WeakSet和WeakMap。
HashMap、字典和哈希是各种编程语言存储键值对的几种方法,这些数据结构针对快速检索进行了优化。
在ES5中,JavaScript对象(只是具有键和值的属性的任意集合)可以模拟哈希,但是使用对象作为哈希有几个缺点。
JavaScript对象属性键必须是字符串,这限制了它们作为不同数据类型键值对集合的能力。当然,您可以将其他数据类型强制转换为字符串,但这会增加额外的工作。
对象并非设计为集合,因此没有有效的方法来确定对象有多少属性。(例如,Object.keys速度很慢)。当您循环遍历对象的属性时,您还会获得其原型属性。您可以向所有对象添加可迭代属性,但并非所有对象都旨在用作集合。您可以使用for … in循环和hasOwnProperty()方法,但这只是一个变通方法。当您循环遍历对象的属性时,属性不一定会按照插入的顺序检索。
对象具有内置方法,如constructor、toString和valueOf。如果将其中一个添加为属性,则可能导致冲突。您可以使用Object.create(null)创建一个裸对象(不继承自object.prototype),但这仍然只是一个变通方法。
ES6包含新的集合数据类型,因此不再需要使用对象并忍受它们的缺点。
Map是我们将要检查的第一个数据结构/集合。Map是任何类型的键值对的集合。创建新的Map、添加/删除值、循环遍历键/值以及有效地确定其大小很容易。以下是关键方法:
<code class="language-javascript">const map = new Map(); // 创建一个新的Map map.set('hobby', 'cycling'); // 设置键值对 const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // 新对象 const normalfoods = {}; // 新对象 map.set(normalfoods, foods); // 设置两个对象作为键值对 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(); // 清除键值对 console.log(map.size === 0); // True </code>
在JSBin上运行此示例
Set是有序的值列表,不包含重复项。Set不是像数组那样被索引,而是使用键访问。Set已经存在于Java、Ruby、Python和许多其他语言中。ES6 Set与其他语言中的Set之间的一个区别是,顺序在ES6中很重要(在许多其他语言中并非如此)。以下是关键的Set方法:
<code class="language-javascript">const planetsOrderFromSun = new Set(); planetsOrderFromSun.add('Mercury'); planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // 可链式方法 console.log(planetsOrderFromSun.has('Earth')); // True planetsOrderFromSun.delete('Mars'); console.log(planetsOrderFromSun.has('Mars')); // False for (const x of planetsOrderFromSun) { console.log(x); // 输入和输出顺序相同 - Mercury Venus Earth } console.log(planetsOrderFromSun.size); // 3 planetsOrderFromSun.add('Venus'); // 尝试添加重复项 console.log(planetsOrderFromSun.size); // 仍然是3,没有添加重复项 planetsOrderFromSun.clear(); console.log(planetsOrderFromSun.size); // 0 </code>
在JSBin上运行此示例
JavaScript垃圾回收是一种内存管理形式,其中不再引用的对象会自动删除,并且其资源会被回收。
Map和Set对对象的引用是强持有的,并且不允许垃圾回收。如果map/set引用不再需要的大的对象(例如已经从DOM中删除的DOM元素),这可能会变得很昂贵。
为了解决这个问题,ES6还引入了两个新的弱集合,称为WeakMap和WeakSet。这些ES6集合是“弱”的,因为它们允许不再需要的对象从内存中清除。
WeakMap是我们介绍的第三个新的ES6集合。WeakMap类似于普通的Map,但方法较少,并且在垃圾回收方面存在上述差异。
<code class="language-javascript">const aboutAuthor = new WeakMap(); // 创建新的WeakMap const currentAge = {}; // 键必须是对象 const currentCity = {}; // 键必须是对象 aboutAuthor.set(currentAge, 30); // 设置键值 aboutAuthor.set(currentCity, 'Denver'); // 键值可以是不同数据类型 console.log(aboutAuthor.has(currentCity)); // 测试WeakMap是否包含键 aboutAuthor.delete(currentAge); // 删除键 </code>
WeakMap有几个流行的用例。它们可以用来保持对象的私有数据私有,也可以用来跟踪DOM节点/对象。
以下示例来自JavaScript专家Nicholas C. Zakas:
<code class="language-javascript">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; }()); </code>
在这里使用WeakMap简化了保持对象数据私有的过程。可以引用Person对象,但是如果没有特定的Person实例,则不允许访问privateDataWeakMap。
Google Polymer项目在一个名为PositionWalker的代码片段中使用WeakMap。
PositionWalker跟踪DOM子树中的位置,作为当前节点和该节点内的偏移量。
WeakMap用于跟踪DOM节点的编辑、删除和更改:
<code class="language-javascript">const map = new Map(); // 创建一个新的Map map.set('hobby', 'cycling'); // 设置键值对 const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // 新对象 const normalfoods = {}; // 新对象 map.set(normalfoods, foods); // 设置两个对象作为键值对 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(); // 清除键值对 console.log(map.size === 0); // True </code>
WeakSet是其元素在不再需要它们引用的对象时可以进行垃圾回收的Set集合。WeakSet不允许迭代。它们的用例相当有限(至少目前是这样)。大多数早期采用者说WeakSet可以用来标记对象而无需修改它们。ES6-Features.org有一个从WeakSet添加和删除元素的示例,以便跟踪对象是否已被标记:
<code class="language-javascript">const planetsOrderFromSun = new Set(); planetsOrderFromSun.add('Mercury'); planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // 可链式方法 console.log(planetsOrderFromSun.has('Earth')); // True planetsOrderFromSun.delete('Mars'); console.log(planetsOrderFromSun.has('Mars')); // False for (const x of planetsOrderFromSun) { console.log(x); // 输入和输出顺序相同 - Mercury Venus Earth } console.log(planetsOrderFromSun.size); // 3 planetsOrderFromSun.add('Venus'); // 尝试添加重复项 console.log(planetsOrderFromSun.size); // 仍然是3,没有添加重复项 planetsOrderFromSun.clear(); console.log(planetsOrderFromSun.size); // 0 </code>
Map和Set是键值对的漂亮的新ES6集合。也就是说,JavaScript对象仍然可以在许多情况下用作集合。除非情况需要,否则无需切换到新的ES6集合。
MDN有一个很好的问题列表,用于确定何时使用对象或键控集合:
JavaScript集合以前非常有限,但这已通过ES6得到纠正。这些新的ES6集合将增强语言的强大功能和灵活性,并简化采用它们的JavaScript开发人员的任务。
本文是来自Microsoft技术布道者和DevelopIntelligence关于实用JavaScript学习、开源项目和互操作性最佳实践(包括Microsoft Edge浏览器和新的EdgeHTML渲染引擎)的Web开发系列的一部分。DevelopIntelligence通过appendTo(其专注于前端的博客和课程网站)提供JavaScript培训和React培训课程。
我们鼓励您在包括Microsoft Edge(Windows 10的默认浏览器)在内的各种浏览器和设备上进行测试,可以使用dev.microsoftedge.com上的免费工具,包括EdgeHTML问题跟踪器,您可以在其中报告或搜索EdgeHTML问题,例如网站渲染或标准合规性问题。此外,请访问Edge博客,以获取来自Microsoft开发人员和专家的最新信息。
在JavaScript ES6中,Map和WeakMap都用于存储键值对。但是,它们之间存在一些显着差异。首先,在Map中,键可以是任何类型,而在WeakMap中,键必须是对象。其次,Map具有size属性,允许您检查键值对的数量,但WeakMap没有此属性。最后,Map对键对象持有强引用,这意味着只要Map存在,它们就没有资格进行垃圾回收。另一方面,WeakMap对键对象持有弱引用,这意味着如果对对象没有其他引用,则可以对其进行垃圾回收。
与Map和Set不同,WeakMap和WeakSet没有迭代其元素的方法。这是因为它们旨在对它们的键(WeakMap)或值(WeakSet)持有弱引用,这意味着这些可以在任何时间进行垃圾回收。因此,无法保证在尝试迭代元素时元素仍然存在。如果您需要迭代集合,则应改用Map或Set。
不可以,您不能在WeakMap或WeakSet中使用原始数据类型作为键。这些集合中的键必须是对象。这是因为WeakMap和WeakSet对它们的键持有弱引用,这意味着如果对它们没有其他引用,则可以对键进行垃圾回收。原始数据类型(例如数字和字符串)不会像对象那样进行垃圾回收,因此它们不能用作这些集合中的键。
WeakMap和WeakSet具有一些独特的特性,在某些情况下,它们可能比Map或Set更合适。因为它们对它们的键(WeakMap)或值(WeakSet)持有弱引用,所以当它们不再使用时,可以对其进行垃圾回收。如果您想将其他数据与对象关联,但又不想阻止对象在不再需要时进行垃圾回收,这将非常有用。此外,因为WeakMap和WeakSet没有迭代其元素的方法,所以它们可以为它们存储的数据提供一定程度的隐私。
当WeakMap或WeakSet中的键被垃圾回收时,集合中的相应条目会自动删除。这是因为这些集合对它们的键持有弱引用,这意味着当它们不再使用时,可以对键进行垃圾回收。此功能对于管理JavaScript应用程序中的内存非常有用,因为它确保与不再使用的对象关联的数据也会被清除。
是的,WeakMap和WeakSet非常适合存储临时数据。因为它们对它们的键(WeakMap)或值(WeakSet)持有弱引用,所以当它们不再使用时,可以对其进行垃圾回收。这意味着当键被垃圾回收时,存储在这些集合中的数据也会被清除。这对于存储仅在短时间内需要的有用,因为您不必担心手动清理它。
您可以使用has方法来检查WeakMap或WeakSet是否包含某个键。此方法返回一个布尔值,指示该键是否存在于集合中。但是,请记住,您不能使用此方法来检查WeakSet中的某个值,因为此集合中的值是不可访问的。
是的,您可以使用delete方法从WeakMap中删除条目。此方法删除与给定键关联的条目,并返回一个布尔值,指示该键是否存在于集合中。但是,您不能从WeakSet中删除条目,因为此集合没有delete方法。
不可以,您不能清除WeakMap或WeakSet中的所有条目。这些集合没有clear方法,该方法在Map和Set中可用。这是因为WeakMap和WeakSet旨在在键被垃圾回收时自动清理它们的条目。
不可以,您无法获取WeakMap或WeakSet的大小。这些集合没有size属性,该属性在Map和Set中可用。这是因为由于垃圾回收,WeakMap或WeakSet的大小可以随时更改。
以上是ES6集合:使用地图,设置,弱图,弱点的详细内容。更多信息请关注PHP中文网其他相关文章!