首页 >web前端 >js教程 >ES6集合:使用地图,设置,弱图,弱点

ES6集合:使用地图,设置,弱图,弱点

Joseph Gordon-Levitt
Joseph Gordon-Levitt原创
2025-02-15 12:37:11825浏览

ES6 Collections: Using Map, Set, WeakMap, WeakSet

本文探讨了四个新的ES6集合以及它们带来的好处。

大多数主要的编程语言都有几种类型的数据集合。Python有列表、元组和字典。Java有列表、集合、映射、队列。Ruby有哈希和数组。到目前为止,JavaScript只有数组。对象和数组是JavaScript的得力助手。ES6引入了四个新的数据结构,它们将增强语言的强大功能和表达能力:Map、Set、WeakSet和WeakMap。

关键要点

  • ES6引入了四个新的数据结构:Map、Set、WeakSet和WeakMap。这些集合允许更具表达性和功能强大的JavaScript编程。
  • ES6中的Map和Set是任何类型的键值对的集合。它们针对快速检索进行了优化,并提供添加、删除和循环遍历值的方法。但是,它们对对象持有强引用,如果对象很大且不再需要,则可能代价很高。
  • ES6还引入了WeakMap和WeakSet,它们类似于Map和Set,但对对象持有弱引用。这意味着当这些对象不再需要时,可以对其进行垃圾回收,这对于内存管理非常有益。
  • 虽然新的ES6集合提供了更大的灵活性,但在许多情况下,JavaScript对象仍然可以用作集合。在决定是否使用对象或键控集合时,开发人员应考虑诸如需要动态键查找、值的互换性和添加或删除键值对的频率等因素。

寻找JavaScript HashMap

HashMap、字典和哈希是各种编程语言存储键值对的几种方法,这些数据结构针对快速检索进行了优化。

在ES5中,JavaScript对象(只是具有键和值的属性的任意集合)可以模拟哈希,但是使用对象作为哈希有几个缺点。

缺点#1:ES5中的键必须是字符串

JavaScript对象属性键必须是字符串,这限制了它们作为不同数据类型键值对集合的能力。当然,您可以将其他数据类型强制转换为字符串,但这会增加额外的工作。

缺点#2:对象并非天生可迭代

对象并非设计为集合,因此没有有效的方法来确定对象有多少属性。(例如,Object.keys速度很慢)。当您循环遍历对象的属性时,您还会获得其原型属性。您可以向所有对象添加可迭代属性,但并非所有对象都旨在用作集合。您可以使用for … in循环和hasOwnProperty()方法,但这只是一个变通方法。当您循环遍历对象的属性时,属性不一定会按照插入的顺序检索。

缺点#3:内置方法冲突的挑战

对象具有内置方法,如constructor、toString和valueOf。如果将其中一个添加为属性,则可能导致冲突。您可以使用Object.create(null)创建一个裸对象(不继承自object.prototype),但这仍然只是一个变通方法。

ES6包含新的集合数据类型,因此不再需要使用对象并忍受它们的缺点。

使用ES6 Map集合

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不是像数组那样被索引,而是使用键访问。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

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。

DOM节点用例

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

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所有事物?记录与ES6集合

Map和Set是键值对的漂亮的新ES6集合。也就是说,JavaScript对象仍然可以在许多情况下用作集合。除非情况需要,否则无需切换到新的ES6集合。

MDN有一个很好的问题列表,用于确定何时使用对象或键控集合:

  • 键通常直到运行时才知道吗?您需要动态查找它们吗?
  • 所有值都具有相同的类型,并且可以互换使用吗?
  • 您是否需要不是字符串的键?
  • 经常添加或删除键值对吗?
  • 您是否有任意数量(易于更改)的键值对?
  • 集合是否被迭代?

新的ES6集合产生更易用的JavaScript

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开发人员和专家的最新信息。

关于ES6集合的常见问题解答 (FAQ):Map、Set、WeakMap、WeakSet

JavaScript ES6中Map和WeakMap的主要区别是什么?

在JavaScript ES6中,Map和WeakMap都用于存储键值对。但是,它们之间存在一些显着差异。首先,在Map中,键可以是任何类型,而在WeakMap中,键必须是对象。其次,Map具有size属性,允许您检查键值对的数量,但WeakMap没有此属性。最后,Map对键对象持有强引用,这意味着只要Map存在,它们就没有资格进行垃圾回收。另一方面,WeakMap对键对象持有弱引用,这意味着如果对对象没有其他引用,则可以对其进行垃圾回收。

如何在JavaScript ES6中迭代WeakMap或WeakSet?

与Map和Set不同,WeakMap和WeakSet没有迭代其元素的方法。这是因为它们旨在对它们的键(WeakMap)或值(WeakSet)持有弱引用,这意味着这些可以在任何时间进行垃圾回收。因此,无法保证在尝试迭代元素时元素仍然存在。如果您需要迭代集合,则应改用Map或Set。

我可以在WeakMap或WeakSet中使用原始数据类型作为键吗?

不可以,您不能在WeakMap或WeakSet中使用原始数据类型作为键。这些集合中的键必须是对象。这是因为WeakMap和WeakSet对它们的键持有弱引用,这意味着如果对它们没有其他引用,则可以对键进行垃圾回收。原始数据类型(例如数字和字符串)不会像对象那样进行垃圾回收,因此它们不能用作这些集合中的键。

为什么我应该使用WeakMap或WeakSet而不是Map或Set?

WeakMap和WeakSet具有一些独特的特性,在某些情况下,它们可能比Map或Set更合适。因为它们对它们的键(WeakMap)或值(WeakSet)持有弱引用,所以当它们不再使用时,可以对其进行垃圾回收。如果您想将其他数据与对象关联,但又不想阻止对象在不再需要时进行垃圾回收,这将非常有用。此外,因为WeakMap和WeakSet没有迭代其元素的方法,所以它们可以为它们存储的数据提供一定程度的隐私。

当WeakMap或WeakSet中的键被垃圾回收时会发生什么?

当WeakMap或WeakSet中的键被垃圾回收时,集合中的相应条目会自动删除。这是因为这些集合对它们的键持有弱引用,这意味着当它们不再使用时,可以对键进行垃圾回收。此功能对于管理JavaScript应用程序中的内存非常有用,因为它确保与不再使用的对象关联的数据也会被清除。

我可以使用WeakMap或WeakSet来存储临时数据吗?

是的,WeakMap和WeakSet非常适合存储临时数据。因为它们对它们的键(WeakMap)或值(WeakSet)持有弱引用,所以当它们不再使用时,可以对其进行垃圾回收。这意味着当键被垃圾回收时,存储在这些集合中的数据也会被清除。这对于存储仅在短时间内需要的有用,因为您不必担心手动清理它。

如何检查WeakMap或WeakSet是否包含某个键或值?

您可以使用has方法来检查WeakMap或WeakSet是否包含某个键。此方法返回一个布尔值,指示该键是否存在于集合中。但是,请记住,您不能使用此方法来检查WeakSet中的某个值,因为此集合中的值是不可访问的。

我可以从WeakMap或WeakSet中删除条目吗?

是的,您可以使用delete方法从WeakMap中删除条目。此方法删除与给定键关联的条目,并返回一个布尔值,指示该键是否存在于集合中。但是,您不能从WeakSet中删除条目,因为此集合没有delete方法。

我可以清除WeakMap或WeakSet中的所有条目吗?

不可以,您不能清除WeakMap或WeakSet中的所有条目。这些集合没有clear方法,该方法在Map和Set中可用。这是因为WeakMap和WeakSet旨在在键被垃圾回收时自动清理它们的条目。

我可以获取WeakMap或WeakSet的大小吗?

不可以,您无法获取WeakMap或WeakSet的大小。这些集合没有size属性,该属性在Map和Set中可用。这是因为由于垃圾回收,WeakMap或WeakSet的大小可以随时更改。

以上是ES6集合:使用地图,设置,弱图,弱点的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn