当前位置: 首页 > 网络应用技术

何时应该在JavaScript中选择地图而不是对象而不是对象

时间:2023-03-07 00:57:22 网络应用技术

  在JavaScript中选择对象和映射

  查看Reddit上的讨论

  在JavaScript中,对象很方便。它们使我们能够轻松地将多个数据组合在一起。ES6后,我们为该语言添加了一个新功能 - 。在许多方面,它似乎更强大,但是接口有点尴尬。但是,大多数人在需要时仍使用散布映射时仍然使用对象,并且只有当他们意识到钥匙不能只使用其字符串的字符串时,他们才能切换以切换用例。因此,它在当今的JavaScript社区中尚未完全使用。

  在本文中,我将分解您应该考虑使用更多原因和基准测试的所有原因和性能特征和基准测试。

  在JavaScript中,对象是一个相当广泛的术语。几乎所有内容都可以是一个对象。除了两种底部类型和。在此博客文章中,对象仅引用普通的旧对象,该对象被左大括号和右支架隔开。

  哈希映射目标最明显的缺点可能是对象仅允许键作为字符串和符号。任何其他类型都会通过这些方法隐式转换为字符串。

  更重要的是,将物体用于哈希映射可能会引起混乱和安全危害。

  在ES6之前,获取哈希映射的唯一方法是创建一个空对象。

  但是,在创建之后,此对象不再是空的。尽管它是由空对象制成的,但它会自动继承。这就是为什么我们可以在这样的方法上称呼它,即使我们从未在对象上定义这些方法。

  由于原型的继承,我们现在与两种类型的属性混合在一起:对象本身中存在的属性,即其自身属性以及原型链中存在的属性,即遗传的属性。因此,我们需要其他检查(例如),以确保给定属性确实是由用户提供的,而不是由原型继承。

  最重要的是,由于JavaScript中属性分析机制的工作方法,运行时的任何更改都将在所有对象中都有链反应。这为原型污染攻击打开了大门,这可能是大型的严重安全问题JavaScript应用程序。

  幸运的是,我们可以通过使用它来解决此问题,该问题将生成一个不继承任何内容的对象。

  当对象的属性与其原型上的属性发生冲突时,它将破坏期望并因此崩溃您的程序。

  例如,我们具有接受对象的功能:

  存在可靠性风险:考虑JavaScript中属性分析机制的工作方法,如果它包含用户提供的同名属性,则它将隐藏。结果,我们不知道运行时将准确调用哪种方法。

  可以执行一些防御性编程以防止这一点。例如,我们可以“借用”和“真实”:

  较短的方法可以称为对象文本上的方法,但仍然很麻烦。这就是为什么有一个新添加的静态方法的原因。

  它没有提供足够的人体工程学来用作BEH映射。无法直观地执行许多常见任务。

  尺寸##没有方便的API来获得大小,即属性的数量。构成对象大小的因素也有很小的差异:

  上述所有选项的复杂性是因为我们必须先构建一个键阵列,然后才能获得其长度。

  迭代#遍历对象也具有相似的复杂性。

  我们可以使用良好的旧周期。但是它揭示了继承的枚举属性:

  我们不能将其与对象一起使用,因为默认情况下它不是迭代的,除非我们在其上明确定义。

  我们可以使用并获得枚举的字符串键(或/和值列表,然后迭代,这将引入其他开销步骤。

  最后,臭名昭著的插入顺序并未得到完全尊重。在大多数浏览器中,整数钥匙由升降机排序并优选为字符串键,在将字符串键插入整数键之前,这种情况就是这种情况。

  清晰#没有简单的方法可以从对象中删除所有属性。您必须使用操作员逐一删除每个属性,这被认为是历史记录缓慢的。但是我的基准测试表明其性能实际上是不可比较的。以后说话。

  检查属性是否存在##最后,我们不能依靠点/括号符号来检查属性是否存在,因为可以将值本身设置为。相反,我们必须使用O。

  ES6带来地图。它更适合哈希映射案例。

  首先,与仅允许字符串和符号的键不同,它支持任何数据类型键。

  但是,如果您使用元数据存储对象,则应使用它来避免内存泄漏。

  但更重要的是,它在用户定义和构建的程序数据之间提供了明确的分离,但是成本是其他检索条目。

  还提供了更好的人体工程学工程:默认情况下,A是迭代的。这意味着您可以使用简单的迭代地图并执行操作,例如使用嵌套解构来从地图中提取第一个条目。

  比较,为各种共同任务提供专用API:

  在大多数情况下,JavaScript社区似乎普遍认为。有些人声称可以切换。

  我的训练leetcode经验似乎证实了这一信念:Leetcode提供了大量数据作为解决方案的解决方案。如果您的解决方案需要太长,则需要超时。这样的问题只会在您使用时需要时间。

  但是,我认为简化了“比对象快”。必须有一些微妙的区别。我想自己找到它。

  重要的演示陈述

  该应用程序的表显示了测量及更高版本的插入,迭代和删除的速度。

  插入和迭代的性能测量每秒操作的数量。我编写了一个util函数,该功能重复运行目标函数,直到达到指定的最小时间阈值(即UI上的输入字段)。它返回平均数量每秒这样的功能。

  至于删除,我只想测量使用操作员从对象中删除所有属性所需的时间,并将其与相同大小的时间进行比较。我可以使用它,但是它违反了基准测试的目的坚信它会更快。

  在这三个操作中,我更加关注插入,因为这通常是我在日常工作中执行的最常见的操作。很难为迭代性能提出一个全面的基准,因为我们可以在一个上执行许多不同的迭代变体给定对象。在这里我只测量周期。

  我在这里使用三种类型的键:

  所有密钥都是随机生成的,因此我们不会遇到V8实现的内部连接。我还将整数和数字明确转换为字符串,然后将它们添加到对象中以避免隐藏的转换开门。

  最后,在基准测试开始之前,预热阶段至少为100毫秒。我们反复创建新对象和地图,将立即丢弃。

  如果您想播放,我将代码放在CodeSandbox上。

  我从100个属性/条目的大小开始,从50,000开始,让每种类型的操作连续运行10,000毫秒,看看它们如何相互执行。这是我的发现...

  当条目数量达到50,000时,为什么我们停止?

  一般而言,当键是(非数字)字符串时,在所有操作中都更好。

  但是,略有区别在于,当条目的数量不大(低于100,000)时,插入速度是插入速度的两倍,但是随着尺寸的增加超过100,000,性能差距开始缩小。

  我制作了一些图表,以更好地解释我的发现。

  上图显示了随着条目数量的增加(x -axis)。插入率如何降低(y轴)。这两条线之间的差距。

  然后,我使用数字量表来处理数据并制作以下图表。

  您可以清楚地看到两行正在融合。

  我制作了另一个图表来绘制与插入速度有关的速度。您可以看到开始的开始。然后,随着时间的推移,性能差距开始缩小。随着量表增加到50,000,000,最终速度仅快30%。

  但是,我们大多数人在一个对象或映射中永远不会有超过100万个条目。在数百或数千个项目中,其性能至少是。因此,我们应该把它留在那里,然后全力以赴重建我们的代码库吗?

  永远不会...或至少不希望我们的应用程序是快速的两倍。

  我特别想测试整数键对象的基准测试。内部对V8的原因进行了优化,即整数索引属性是优化的,它们存储在一个可以线性且可连续访问的单独数组中。我找不到任何资源来确认它已经优化了相同类型的S。

  让我们尝试[0,1000]范围内的整数键。

  正如我所期望的那样,这次我赢得了大型市场。它们的插入速度比地图快65%,并且迭代速度快16%。

  让我们扩展范围,以使密钥1200中的最大整数。

  现在,它的启动速度比插入对象和5次迭代更快。

  现在,我们只添加整数键的范围,而不是和谐的实际尺寸。让我们增加大小并了解其影响性能。

  当属性大小为1,000时,它最终比插入快70%,并且它的迭代速度是慢的两倍。

  我播放了一堆不同的/大小和整数键的组合,但是我没有提出清晰的图案。在插入中高于s。它总是与删除。最大整数键的阈值开始减慢对象的插入速度随着对象的大小而增加。例如,当对象只有100个项目时,阈值为1200;当它有10,000个条目时,阈值似乎约为24,000。

  最后,让我们看一下最后一个密钥 - 数字键。

  从技术上讲,以前的整数密钥也是数字。这里的数字密钥专门指的是数字数。

  结果类似于那些字符串键:S的速度比开始时的对象快得多(插入和删除的速度是两倍,速度快4-5倍),但是随着我们增加尺寸,增量变得越来越小。

  嵌套对象/地图呢?

  基准测试的另一个重要方面是内存利用。

  由于我无法控制浏览器环境中的垃圾收集器,因此我决定在Node.js中运行基准测试。

  我创建了一个小脚本来测量其各自的内存使用情况并在每个测量中手动触发完全垃圾收集。

  显然,它比任何地方都消耗了20%至50%,这并不奇怪,因为它不存储属性描述符,例如//。

  那么我们可以从所有这些中得到什么呢?

  如果您知道如何优化V8,或者只是想指出我的基准测试中的缺陷,请与我联系。我很高兴根据您的信息更新本文!

  它是ES6的特征。到目前为止,我们大多数人都不必担心它的兼容性,除非您的目标用户群是一些利基浏览器。“旧”表示比IE 11更早,因为即使IE 11支持MAP,IE 11都死了目前。我们默认不应盲目地翻译和添加polyfill,因为它不仅会扩大您的行李尺寸,而且与现代JavaScript相比,它的运行速度也缓慢。最重要的是,它将惩罚99.999%使用现代浏览器的用户。

  此外,我们不必放弃对浏览器的旧版本的支持 - 通过提供骨干来提供旧代码,以便我们可以避免使用现代浏览器来减少访客的体验。令人信服的是,请参考过渡到现代JavaScript。

  JavaScript语言正在不断发展,该平台在优化现代JavaScript方面越来越好。我们不应忽略浏览器兼容性的所有改进作为借口。

  转载在https://www.zhenghao.io/posts/object-ds-ds-ds

  原始:https://juejin.cn/post/711306242703337864