停止滥用.map()!

2025-05-24

停止滥用.map()!

每当我进行代码审查或访问 StackOverflow 时,我都会偶然发现如下代码片段:

const fruitIds = ['apple', 'oragne', 'banana'];
fruitIds.map((id) => {
   document.getElementById(`fruit-${id}`).classList.add('active');
});
Enter fullscreen mode Exit fullscreen mode

因此,正如您所看到的,这只是一个简单的迭代,其中对于fruitIds数组中的每个元素,我们将active类添加到 DOM 中的某个 HTML 元素。

许多程序员(尤其是新手)不会注意到上面的代码有什么问题。然而,这里有一个主要问题—— 的使用.map()。让我解释一下。

有什么问题.map()

嗯,这个特定的数组方法完全没有问题。事实上,我认为它非常方便,并且完美地包装了迭代模式之一—— mapping

简单来说,映射是一种将函数应用于集合中每个元素的操作,并返回一个元素被该函数修改的新集合。例如,如果我们有一个数字数组,const nums = [1, 2, 3, 4];并且想要接收一个包含双倍数字的新数组,我们可以将原始数组映射到一个新的数组,如下所示(在 JavaScript 中):

const biggerNums = nums.map((n) => n * 2);
// >> [2, 4, 6, 8];
Enter fullscreen mode Exit fullscreen mode

biggerNums数组将由原始nums数组中的数字乘以组成2

注意 的.map()使用方式——我们将该方法的结果赋值给一个名为 的新变量biggerNums。我之前也提到过,映射操作会返回一个新的元素集合。而这正是本文开头代码片段错误的原因。总是.map()会返回一个新数组——如果我们不需要这个数组,就不应该使用它。在这种特殊情况下(简单迭代),应该使用专门为这种情况设计的另一种数组方法。它不会返回新的集合,而只是遍历数组并为每个元素调用一个回调函数,从而允许您对每个元素执行某些操作。.map().forEach()

因此,上述代码片段的正确版本应如下所示:

// good way
const fruitIds = ['apple', 'oragne', 'banana'];
fruitIds.forEach((id) => {
   document.getElementById(`fruit-${id}`).classList.add('active');
});
Enter fullscreen mode Exit fullscreen mode

我们不需要新的数组,因此我们只需遍历该fruitIds数组并将类添加active到每个数组项的 HTML 元素中。

好吧,但我为什么要关心呢?.map()比 更短也更容易写.forEach()。可能会出什么问题?

滥用的后果.map()

滥用此方法最严重的后果之一.map()是它会返回一个新的冗余数组。更具体地说,它会返回一个与调用此方法时大小相同的新数组。这意味着,如果我们有一个包含 1000 个元素的数组,每次.map()都会返回一个包含 1000 个元素的新数组

在 JavaScript 中,所有函数都会返回一个值。即使我们不使用return关键字,函数也会undefined隐式返回。这就是 JavaScript 的设计初衷。这条规则也适用于回调函数——它们也是函数。

话虽如此,让我们回到最初的例子:

// wrong way
const fruitIds = ['apple', 'oragne', 'banana'];
fruitIds.map((id) => {
   document.getElementById(`fruit-${id}`).classList.add('active');
});
Enter fullscreen mode Exit fullscreen mode

这里发生了什么?创建一个水果 ID 数组,然后将其映射到另一个相同大小的数组。即使返回的数组.map()未被使用,它仍然占用内存。这个新的(未使用的)数组如下所示:

[undefined, undefined, undefined]
Enter fullscreen mode Exit fullscreen mode

这是因为传递给方法的回调.map()没有return关键字,而且我们知道,如果没有returnundefined则会隐式返回。

它有多糟糕?非常糟糕。在这个特定的例子中,它不会带来任何严重后果——数组中只有三个项目,所以创建另一个三元素数组不会导致任何问题。然而,当我们处理复杂数据的大型数组时,问题就出现了。如果我们想要迭代一个包含五千个对象的数组,并且我们滥用了.map(),我们会创建另一个包含五千个元素的数组undefined——s。因此,我们最终在内存中存储了 10,000 个元素,其中整整一半是多余的。这是一种非常非最佳的做法,在某些情况下甚至可能导致应用程序过载。这就是为什么我们应该为正确的任务选择正确的方法。

概括

很多做法本质上都是错误的,但只有在处理更大的数据集时,其负面影响才会显现。滥用 就是其中一种.map()。在处理小数组时,它不会造成任何损害。但当我们在处理更大的数组时犯下这种错误,它会导致应用程序过载,并且可能很难调试。

这就是为什么我们绝不应该放任这种虐待行为,无论何时看到这种虐待,我们都应该予以处理。我希望现在你明白了。

文章来源:https://dev.to/catchmareck/stop-abusing-map-51mj
PREV
正则表达式速查表 为所有正则表达式憎恨者(和爱好者)准备的正则表达式速查表 👀 我使用正则表达式的经验 速查表资源
NEXT
REST API 基础知识