在不使用返回值的情况下执行映射操作是一种反模式吗?

Is performing a mapping operation without using returned value an antipattern?

假设我有一个列表,我想使用映射函数向其中添加一些值:

const arr = [1, 2, 3, 4, 5];
const anotherArr = [];

我使用函数式方法执行此操作:

arr.map((item) => anotherArr.push(item));

这是反模式/错误逻辑吗?也就是说,没有对任何内容使用映射操作 return 值?有这方面的好资源吗?

(我知道这个逻辑很愚蠢,我可以复制列表 - 这不是我的问题的重点)

是的,这是 anti-pattern。尽管您可能会争辩说它不是,而且它只是简单的滥用。我将其称为 anti-pattern,因为出于某种原因, 经常发生的广泛事件,人们在不应该使用 .map() 的情况下使用

该术语来自 mathematics,您可以在其中 映射 从一个类别到另一个类别。例如,形状 (X) 到颜色 (Y):

(图片来自维基百科)

该术语在 computer science 中也得到了很好的确立,其中 map() 是执行此类转换的高阶函数。在JavaScript中,它是一个数组方法并且有明确的用法——将一个数组的内容转换为另一个数组的内容。给定数组 X = [0, 5, 8, 3, 2, 1] 我们可以使用 .map() 方法将 x => x + 1 应用于它。

(图片来自维基百科)

这 wide-reaching 不仅仅是实现的细节 - .map() 惯用的 如果误用会使代码更难阅读和理解。让我们做一个 step-by 步骤示例:

我们需要一个映射函数来表达元素之间的关系。例如,将一个字母转换到它在字母表中的位置可以通过函数表示:

function letterToPositionInAlphabet(letter) {
  return letter.toUpperCase().charCodeAt(0) - 64;
}

通过此函数映射一个字母数组将为我们提供一个包含每个字母位置的数组:

function letterToPositionInAlphabet(letter) {
  return letter.toUpperCase().charCodeAt(0) - 64;
}

const letters = ["a", "b", "c"];

console.log(letters.map(letterToPositionInAlphabet));

映射操作是成语,也是理解代码的一部分。如果你看到 someArr.map(someFn) 它建立了预期并且很容易理解正在发生什么样的操作,而不需要知道数组或函数的内容。当您看到 letters.map(letterToPositionInAlphabet) 时,理解其意图应该是微不足道的 - 获取某些字母在字母表中的位置。这是 self-documenting 代码,我们可以假设代码是正确的,除非另有证明。

但是,将 .map() 用作 .forEach() 会破坏预期的含义,并且可能会造成阅读混乱。考虑这个

function playerToPlaceInRankList(player) {
   const position = lookupPlayerRank(player);
   positionsArr.push(position);
}

/* many lines later */

players.map(playerToPlaceInRankList);

/* more code */

执行映射看起来像的行也立即看起来是错误的,因为return值被忽略了。要么不需要该行,要么您必须检查 playerToPlaceInRankList 做了什么才能找出这里实际发生的事情。对于仅仅阅读应该是 straight-forward 和 self-documenting 行的代码来说,这是不必要的精神负担。

这同样适用于使用其他方法,如 .filter().find().every().some() 等。不要仅仅因为它们遍历数组就使用它们, 如果你想要的不是他们想要做的。