发布于 2026-01-06 3 阅读
0

精简的力量:优化 JavaScript 代码以提高速度和效率

精简的力量:优化 JavaScript 代码以提高速度和效率

大家好!这是我的第一篇帖子!

本文将探讨JavaScript 数组reduce方法,我觉得这个方法有时会被人忽略。我会先简要介绍一下 reduce 方法,然后将其与其他迭代方法进行比较。

TLDR

  • 检查你的数组迭代过程。
  • 使用;mapfilterreduce
  • 散布(例如[...list])大型列表是个坏主意;送至list instead
  • reducemap和更快filter,并且for in适用于大型列表

个人笔记

我是一名前端开发人员,工作经验不到两年,这是我的第一篇文章

我这么说是想让你们知道我还是个新手,所以欢迎大家提出任何反馈意见,无论是关于技术内容、写作还是个性(请保持建设性)。

动机:通往单循环的路径

在审查一些人的代码(有时也包括我自己的代码😬)时,我意识到很容易对数组进行不必要的迭代,而这有时reduce可以改进代码。

例如,如果我有一个人员列表,并且想要获取所有成年人的姓名列表,很容易想到:“首先我需要遍历filter列表,获取所有成年人(在我所在的国家/地区年龄大于 18 岁),然后我需要遍历map列表并返回他们的姓名”。
我相信箭头函数使这种思考更加容易,因为它消除了编写循环语句的需要function

然而,为什么不遍历人员列表,并将成年人的名字添加到空列表中呢?简而言之,就是这个reduce意思。虽然有时人们也会忽略这种方法,但
使用循环也能轻松实现这一点。for


减少方法介绍

接下来我将简要介绍一下该reduce方法的工作原理,如果您已经熟悉该方法,请直接跳到基准测试部分。

理论

在 JavaScript 中,我们有多种方法可以遍历数组,例如map`if`、for`if` 或 `if` reduce。最后一种方法或许是三种方法中最不“友好”和常用的,但它也十分重要,我们稍后会看到。

该方法接收两个参数:

  • 一个回调函数,用于返回每次迭代中累积的值;
  • 一个初始值,将用于开始累积。

回调函数本身最多可以接收四个参数:

  • accumulator有时称为total或缩写为acc)是每次迭代中“添加”的值;
  • currentValue正在迭代的数组的当前元素
  • (可选)数组currentIndex元素的位置。常用;currentValue
  • 可选参数,用于指定要迭代的数组。由于通常迭代的是之前声明的变量,因此很少使用此选项。不过,它仍然很有用,因为如果链式调用方法(例如,调用 `sorted( initialArray.sort(...).reduce(...))`),则数组参数将是排序后的数组,而不是初始数组。

你可能会注意到我使用了与累积相关的术语。这是因为 reduce 函数的作用就是累积:它从一个值开始,每次迭代都会将一个值“加”到该值上(我加了引号,因为不一定涉及代数加法)。

我们来看一段代码:

实际案例

我只想给你一些使用 reduce 的基本例子,因为我的目标不是让你成为reduce专家(我也不声称自己是),而是让你记住这个方法。

获取所有成年人的姓名。
让我们回顾一下前面的例子。如果对 `A`map和 `B` 也执行相同的操作filter,则可以这样做:

peopleList.filter((person) => person.age >= 18)
          .map((adult) => adult.name);
Enter fullscreen mode Exit fullscreen mode

使用reduce,你会做类似这样的事情:

peopleList.reduce((acc, person) => {
  if (person.age >= 18) acc.push(person.name);
  return acc;
}, []);
Enter fullscreen mode Exit fullscreen mode

这样一来,你只需要用到一个循环而不是两个。这样是不是就不那么“友好”了?你来告诉我。

还有很多其他用途reduce和使用方法。我选择使用 `<div>`,arrow function但如果你不想用也可以。在这个CodePen中,你可以找到:

  • map对和filterfor in之间检索成年人姓名的比较reduce
  • 另一个例子是计算列表中所有数字的总和。这是使用 . 时引入的一个典型示例reduce

    我之所以不在这里详细解释,是因为我不想让“它reduce只能用于计算”这种观念在你脑海中根深蒂固。没错,它确实可以用于计算,但并非仅限于此,正如一位老师曾经告诉我的那样。

    在这个例子中,我还详细介绍了如何将其reduce与常规函数和内联返回一起使用;


基准测试迭代方法

了解我的人都知道,我有点痴迷于避免重复劳动,提高速度和表现。

这就是我文章的由来。

map我想测试一下和filter、 和之间在性能上是否存在差异reduce。然后我决定也把 加入for in到测试中。

终身学习!

所以我做了一个初步的基准测试,很快就发现了一个问题:

传播会减慢reduce方法速度!

你看,在reducer 函数中,我是acc这样返回的:

return condition ? [...acc, item] : acc;
Enter fullscreen mode Exit fullscreen mode

对于短列表来说,这并不是什么大问题,但是对于非常大的列表来说,这种语法使得该reduce方法速度慢了很多(您将会看到)。

当我第一次开发基准测试并发现reduce(我在文章中提倡的方法)速度比之前慢得多时,我感到非常惊讶map and filter!然而,经过一番研究,我发现这是因为每次迭代都会创建一个对象,并将成千上万个元素分布到该对象上,因此需要改变策略:

if(condition) acc.push(item);
return acc;
Enter fullscreen mode Exit fullscreen mode

现在,每当我在我的项目中使用它时,我不会传播它reduce而是将项目送到。acc

基准

因此,为了开发我的基准测试,我创建了另一个CodePen 示例,其中:

  • 生成一个包含 100,000 个随机数的列表;
  • 每种方法运行某个任务 100 次,每次执行都进行计时;
  • 每种方法都取平均值;无论迭代次数和方法如何,任务本身都是获得小于 16 的二进制转换数字。这不是一个“现实世界”的例子,但足以达到这个目的。

你会看到我添加了使用 spreadpush 的reduce方法,这样你就可以看到性能上的差异。那么,让我们看看哪种方法最快。

结果:获胜者是……

减少!当然了reduce。如果不是这样,我就不会写这篇文章了。😄

迭代方法时间比较

你会注意到我没有在图表中添加reduce使用spread 方法的时间,因为它长达8.8(比 push 方法慢 3000 多倍)!所有其他方法的测量单位均为毫秒

如您所见,三种迭代方法之间的差异并不大,但这并不能改变 `a`map和 ` filterb` 比 `c` 慢 3 毫秒的事实reduce。当然,对于较小的列表,这种差异将微乎其微。

关于这一基准,需要考虑以下几点

  • 这段代码看起来可能过于复杂,但这是我找到的避免在每次迭代或方法中重新创建函数的最佳方法。
  • 我把列表长度增加到了一个可能不太合理的程度。很少有项目会处理包含成千上万个元素的列表。但如果你确实需要这样做,而且网站性能是一个重要问题,那么减少列表长度就是你的好朋友;
  • 纯 JavaScript 通常不会处理大型列表。处理大型列表有多种方法,例如虚拟化分页,因此请注意。
  • 我展示的运行时间是在CodePen上运行代码获得的,因此在生产环境中,在服务器上执行速度可能会更快。

就这些啦!
感谢阅读我的第一篇文章,希望对你有所帮助(否则,我不会退还你花费的时间)。

参考文献和链接

文章来源:https://dev.to/red-dial/the-power-of-reduce-optimizing-javascript-code-for-speed-and-efficiency-3jba