在不使用返回值的情况下执行映射操作是反模式吗? [英] Is performing a mapping operation without using returned value an antipattern?

查看:19
本文介绍了在不使用返回值的情况下执行映射操作是反模式吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我使用函数式方法来做到这一点:

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

这是一个反模式/错误的逻辑——也就是说,不使用映射操作返回值做任何事情吗?这方面有什么好的资源吗?

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

解决方案

是的,这是一种反模式.尽管您可能会争辩说它不是,但它只是简单的误用.我将其称为反模式,因为由于某种原因, 经常发生人们在不应该使用 .map() 的情况下使用它们的普遍事件.

该术语来自(图片来自维基百科)

该术语在 (图片来自维基百科)

这不仅仅是实现的细节影响更广泛 - .map()惯用的,如果误用会使代码更难阅读和理解.让我们做一个循序渐进的例子:

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

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

通过这个函数映射一个字母数组会给我们一个包含它们每个位置的数组:

function letterToPositionInAlphabet(letter) {返回 letter.toUpperCase().charCodeAt(0) - 64;}const 字母 = ["a", "b", "c"];console.log(letters.map(letterToPositionInAlphabet));

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

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

function playerToPlaceInRankList(player) {const position = lookupPlayerRank(player);positionArr.push(position);}/* 多行之后 */玩家地图(playerToPlaceInRankList);/* 更多代码 */

它执行映射看起来像的那一行也立即看起来是错误的,因为返回值被忽略了.要么不需要该行,要么您必须检查 playerToPlaceInRankList 做了什么,以找出此处实际发生的情况.仅仅阅读应该是直接和自我记录的代码行,这是不必要的精神负担.

同样适用于使用其他方法,如 .filter().find().every().some() 等.不要仅仅因为它们遍历数组而使用它们,如果您想要的不是它们的本意.

Lets say I have a list and I want to add some values into it using a mapping function:

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

I do this using a functional approach:

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

Is this an antipattern / bad logic - that is, not using the mapping operation return value for anything? Are there any good resources on this?

(I know this logic is silly and I can just copy the list - that is not the point of my question)

解决方案

Yes, this is an anti-pattern. Although you could argue it is not and it is just plain misuse. I would call it an anti-pattern because for some reason there is a frequent widespread incidents of people using .map() when they should not.

The term comes from mathematics where you can map from one category to another. For example, shapes (X) to colours (Y):

(image from Wikipedia)

The term is also well established in computer science where map() is a higher order function doing this sort of conversion. In JavaScript, it is an array method and has clear usage - to transform the contents of one array into another. Given array X = [0, 5, 8, 3, 2, 1] we can apply x => x + 1 to it using the .map() method.

(Image from Wikipedia)

This is more wide-reaching than just the specifics of the implementation - .map() is idiomatic and if misused makes code harder to read and understand. Let's do a step-by step example:

We need a mapping function that expresses the relationship between elements. For example, transforming a letter to its position in the alphabet can be expressed via the function:

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

Mapping an array of letters via this function will give us an array with each of their positions:

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

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

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

The mapping operation is an idiom and part of understanding the code. If you see someArr.map(someFn) it sets up expectations and it is easy to understand what sort of operation is happening, without needing to know the contents of either the array or the function. When you see letters.map(letterToPositionInAlphabet) it should be trivial to understand what the intent is - get the positions in the alphabet of some letters. This is self-documenting code, we can assume the code is correct unless proven otherwise.

However, using .map() as .forEach() is breaking that intended meaning and can be confusing to read. Consider this

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

/* many lines later */

players.map(playerToPlaceInRankList);

/* more code */

The line which seems like it performs mapping also immediately looks wrong because the return value is ignored. Either that line is not needed, or you have to examine what playerToPlaceInRankList does in order to find out what is actually happening here. That is unnecessary mental load for just reading what should be a straight-forward and self-documenting line of code.

The same applies to using other methods like .filter(), .find(), .every(), .some(), etc. Do not use those just because they iterate over the array, if what you want is not what they are intended to do.

这篇关于在不使用返回值的情况下执行映射操作是反模式吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆