发布于 2026-01-05 13 阅读
0

9 个像专业人士一样使用 JavaScript 数组方法的实用技巧!DEV 全球展示挑战赛,由 Mux 主办:展示你的项目!

9 个让你像专业人士一样使用 Javascript 数组方法的实用技巧!

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

作为一名开发者,我总是会反思自己编写和阅读的代码。在这个过程中,我积累了不少实用技巧。
在这篇文章中,我将分享一些与数组方法相关的技巧。

虽然我这里讨论的是数组方法,但这些技巧也适用于其他情况。编写代码时请牢记这些技巧。

提示

有些是更好的命名规范和应用规则。
有些是让代码更简洁的小技巧。
大多数都带有很强的个人观点😄。

我尝试将它们分为一般性建议具体建议,以便更容易理解和用作参考。


📚目录


一般提示

给你的函数命名

未来的代码阅读者不应该需要费心去思考某个函数的作用。请做个好人,使用有意义的函数名。

const numbers = [1,2,3,4];

 // BAD - I need to think about what this function is doing
numbers.filter(num => num % 2 === 0);

// GOOD - I can read this line and immediately tell what's going on.
const isEven = num => num % 2 === 0);
numbers.filter(isEven); 
Enter fullscreen mode Exit fullscreen mode

不要将参数从一个函数传递给另一个函数。

数组方法会调用接收到特定参数的函数。无需显式地将这些参数传递给另一个函数。

const numbers = [1,2,3,4];
const multiplyByTwo = num => num * 2;

// BAD - There is no need to explicitly pass num.
numbers.map(num => multiplyByTwo(num));

// GOOD 
numbers.map(multiplyByTwo); 
Enter fullscreen mode Exit fullscreen mode

使用部分应用程序

你需要的不仅仅是数组方法传递的数据吗?使用部分应用。

不知道什么是部分申请?看看这个

const numbers = [1,2,3,4];

// BAD
const multiplyBy = (num, multiplier) => num * multiplier;
numbers.map(num => multiplyBy(num, 2));

const multiplyBy = multiplier => num => num * multiplier;
// GOOD
numbers.map(multiplyBy(2)); 

// GOOD - more verbose
const multiplyByTwo = multiplyBy(2);
numbers.map(multiplyByTwo); 
Enter fullscreen mode Exit fullscreen mode

断开长链或将其分配给变量/函数

当我看到三四层数组方法串联在一起,却没有任何迹象表明结果时,我会问自己:为什么?为什么我必须逐行检查,才能弄清楚结果是什么?
有两种方法可以解决这个问题。

  1. 打破链条——将每一行的结果赋值给一个变量,并对该变量进行操作。
  2. 将结果赋值给一个具有有意义名称的函数或变量。

假设我们要找到所有 18 岁以上的员工,给他们随机发放奖金,然后计算他们的工资总和。

const employees = [{name:"bruce banner", age:21, salary: 1500}, ...];
const isAboveEighteen = (employ) => employ.age > 18;
const addRandomBonus = (employ) => ({...employ, salary: employ.salary*(Math.random() + 1)});
const toSumOfSalaries = (sum, employ) => sum + employ.salary;

// BAD - I need to think how each line effect the next one and what will be the outcome
employees
  .filter(isAboveEighteen)
  .map(addRandomBonus)
  .reduce(toSumOfSalaries);

// Breaking the chain
const aboveEighteenEmployees = employees.filter(isAboveEighteen);
const salariesWithBonus = aboveEighteenEmployees.map(addRandomBonus);
const sumOfSalaries = salariesWithBonus.reduce(toSumOfSalaries);

// Assign the result
// *If we need to reuse this then we would use a function
const aboveEighteenAfterBonusSumOfSalaries = employees
      .filter(isAboveEighteen)
      .map(addRandomBonus)
      .reduce(toSumOfSalaries);

Enter fullscreen mode Exit fullscreen mode

地图提示

将类型 A 转换为类型 B 时,请使用“toB”作为函数名,并使用“A”或“fromA”作为函数参数。

例如,假设我们想将错误代码转换为人类可读的错误信息。

在这个例子中,AerrorCodeBerrorMessage

const errorCodes = [1, 2, 3]; 
const errorCodesMessages = {1: "your code is great!", 2: "your code is awesome!".... };

const toErrorMessage = (fromErrorCode) => errorCodesMessages[fromErrorCode];
errorCodes.map(toErrorMessage);
Enter fullscreen mode Exit fullscreen mode

在这个例子中,从代码中可以清楚地看出我们的意图。
toErrorMessage函数表明我们正在将 A 转换为B。我们的数组应该告诉我们正在处理错误代码。但是,如果我们搞砸了数组的命名,那么从函数参数中
就会看出我们正在处理A。

执行操作

我们可以使用与上例相同的约定,但这感觉有点别扭,也过于冗长。
所以,对于动作,我们只需直接陈述我们正在执行的动作即可。

假设我们要给一个用户数组添加一个唯一 ID。

const users = [{name: "john doe", email: "johnDoe@evilcorp.com"}, ....];
const addId = obj => ({...obj, id: uuid()});
users.map(addId);
Enter fullscreen mode Exit fullscreen mode

滤嘴

只有在它是完成这项工作的合适工具时才使用它。

什么时候才是filter合适的工具?当你想根据某个条件获取数组的子集时。
在其他情况下,例如你想获取特定成员、断言某个条件对至少一个成员或所有成员都成立时,可以使用 `__getitem__`、`__getitem__`findsome` every__getitem__`——了解你的工具以及何时使用它们

不太了解这些方法?阅读相关资料查找一些方法以及所有方法。

const peoples = [{ name: "Bruce Wayne", country: "USA", city: "Gotham",... }, ...];

// find
const isBruceWayne = person => person.name === "Bruce Wayne";
peoples.filter(isBruceWayne)[0]; // BAD
peoples.find(isBruceWayne); // GOOD 

// some
const isFromTheUSA = person => person.country === "USA";
// has peoples from USA?
!!peoples.filter(isFromTheUSA)[0];  // BAD
peoples.some(isFromTheUSA);  // GOOD

// every
const isNotFromTheUSA = person => person.country !== "USA";
// everyone from the USA?
!peoples.filter(isNotFromTheUSA)[0]  // BAD
peoples.every(isFromTheUSA)  // GOOD
Enter fullscreen mode Exit fullscreen mode

把它说得像个问题

这条规则适用于所有条件语句。
如果函数的返回值是 ` booleannull`truefalse`undefined`,那么我们应该把函数写得像一个问句。

const numbers = [1,2,3,4]

// BAD - Reads like a statment
const even = num => num % 2 === 0);
numbers.filter(even);

// GOOD - Reads like a question
const isEven = num => num % 2 === 0);
numbers.filter(isEven); 
Enter fullscreen mode Exit fullscreen mode

一些常见的前缀有is,,has……should

一次检查多个条件

如果要一次性检查多个条件,可以使用ramda anyPassallPass函数;如果要结合多个条件并遵循SRP ,则可以使用这些函数。

例如,假设我们想要得到所有大于 10 的偶数,或者所有小于 10 的奇数。

import R from 'ramda';
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
// This is a simple example but you can imagine how it can get out of control.
const isAValidNumber = num => {
  if (num % 2 === 0 && num > 10) {
    return true;
  }
  if (num % 2 && num < 10) {
    return true;
  }
};

// Good - We've split our logic into small, reusable functions, that do one thing.
const isEven = num => num % 2 === 0;
const isOdd = num => !isEven(num);
const isBiggerThanTen = num => num > 10;
const isSmallerThanTen = num => num < 10;
const isValidNumber = R.anyPass([
  R.allPass([isBiggerThanTen, isEven]),
  R.allPass([isSmallerThanTen, isOdd]),
]);
numbers.filter(isValidNumber);
Enter fullscreen mode Exit fullscreen mode

我们添加了一些代码,但你看,我们想要实现的目标非常明确!

如果你不喜欢函数式编程方法,或者你的团队不熟悉函数式编程ramda,还有其他方法可以得到相同的结果,例如将我们编写的函数插入到if函数的第一个实现中的语句中isValidNumber

想用 map 一次性应用多个函数吗?试试ramda pipecompose 吧


有什么建议可以分享吗?

以上就是我使用数组方法的一些心得体会。
你有什么自己的技巧吗?这篇文章里有没有你发现的新东西或有趣的内容?
欢迎留言并分享给你的开发者朋友们😄

文章来源:https://dev.to/galelmalah/9-great-tips-to-use-array-methods-like-a-pro-dcc