了解JavaScript中的高阶函数

100 阅读5分钟

不管是什么语言,你都需要在你的程序中对数据进行迭代或循环。在JavaScript中,我们有几个循环结构可以做到这一点,还有所谓的高阶函数。这些高阶函数允许使用更简洁的语法,允许你在一个集合上进行迭代,同时根据你的需要对集合中的每个项目应用你所选择的逻辑。它们有时有点棘手,所以我们将在本教程中练习大量的函数。我们将研究for、forEach、for of、for in、filter、map、sort和reduce。


我们需要一些数据

我们可以在一组简单的数据上进行练习。这里有一个对象数组和一个数字数组,我们将用它来练习。

//  Array of objects
const companies = [
  { id: 1, name: "Square", sector: "Finance", founded: 2009 },
  { id: 2, name: "Disney", sector: "Media", founded: 1923 },
  { id: 3, name: "Ford", sector: "Auto", founded: 1903 },
  { id: 4, name: "Netflix", sector: "Media", founded: 1997 },
  { id: 5, name: "Apple", sector: "Technology", founded: 1976 },
  { id: 6, name: "Visa", sector: "Finance", founded: 1958 },
  { id: 7, name: "Tesla", sector: "Auto", founded: 2003 },
  { id: 8, name: "Microsoft", sector: "Technology", founded: 1975 },
  { id: 9, name: "Roku", sector: "Media", founded: 2002 }
];

//  Array of numbers
const numbers = [32, 15, 20, 16, 52, 54, 11, 49, 31, 19, 75, 42, 45, 68, 30];

我们还将使用这个封装函数,这样我们就可以在浏览器窗口中看到结果,而不必手动打开控制台。

function output(data) {
  document.write(data + "<br/>");
}

for

好了!现在让我们从一些基本的循环开始,这样我们就可以看到当我们进入高阶函数时,事情的运作会有一些不同。首先是基本的 **for**循环。我们想在所有的公司中进行循环并输出它们的名字。

for (let i = 0; i < companies.length; i++) {
  output(companies[i].name);
}

javascript for loop


forEach

为了做同样的事情 forEach做同样的事情,我们可以使用这种风格的代码。

companies.forEach(function(company) {
  output(company.name);
});

javascript forEach loop


for of

这个 for of循环将看起来像这样。

for (let company of companies) {
  output(company.name);
}

for in

通过这个 **for in**循环,我们可以遍历一个对象的所有键值对。通过这段代码,我们遍历我们公司数组中第4个对象的属性。

for (let property in companies[3]) {
  output(property + ": " + companies[3][property]);
}

javascript for in loop


过滤器

filter函数是我们可以看的第一个高阶函数。如果你写React代码,你会一直使用filter!这个函数是用来根据一个条件访问一个数组的子集。假设我们只想要我们的数字数组中小于或等于20的数字。在使用过滤器之前,我们必须使用这样一个for循环。

let twenty = [];
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] <= 20) {
    twenty.push(numbers[i]);
  }
}

javascript filter behavior using for

使用 filter函数,我们可以实现同样的结果。

const twenty = numbers.filter(data => {
  if (data <= 20) {
    return true;
  }
});

javascript filter example

为了进一步简化这个过程,你可以使用这个简单的单行线

const twenty = numbers.filter(num => num <= 20);

javascript filter example

现在让我们用公司的对象数组和过滤函数一起工作。假设我们只想输出金融行业的公司。没问题!

const financeCompanies = companies.filter(function(company) {
  if (company.sector === "Finance") {
    return true;
  }
});

financeCompanies.forEach(data => output(data.name));

javascript filter on array of objects

我们可以使用过滤函数来寻找在20世纪70年代成立的公司,就像这样。

const seventiesCompanies = companies.filter(
  company => company.founded >= 1970 && company.founded < 1980
);

seventiesCompanies.forEach(company => output(company.name));

而看起来苹果和微软是在七十年代成立的。
js filter function example

请注意,我们给箭头函数的参数起的名字可以是任何我们想要的。大多数时候,你会使用一个对你有意义的命名规则,但作为一个例子,下面的代码产生的结果是完全一样的。

const seventiesCompanies = companies.filter(
  tomato => tomato.founded >= 1970 && tomato.founded < 1980
);

seventiesCompanies.forEach(cucumber => output(cucumber.name));

这总是让我有点困惑,所以希望这个小提示能为你(和我)解惑。

这里是过滤功能的另一个例子,我们找到了经营40年以上的公司。这一切只需要一个简单的单行代码。(第二行代码只是为了在浏览器中显示结果)。

const fortyYears = companies.filter(company => 2019 - company.founded >= 40);

fortyYears.forEach(company => output(company.name));

disney ford apple visa microsoft

就像我们前面提到的,你会用React的过滤函数,所以这是一个很好的练习。


地图

现在我们可以继续使用 map函数。那么,map函数为我们做了什么?map函数用于创建一个新的数组,该数组保存了对原数组中每个元素调用一个给定函数的结果。所以,你拿着一个数组,在每个元素上调用一个函数,从而填充一个新的数组。让我们看几个如何使用map函数的例子。

我们可以把每个公司的名字摘出来,比如说,把它放到一个新的数组中。

const newArray = companies.map(company => company.name);

newArray.forEach(company => output(company));

javascript map function example

我们可以用map来运行一个函数,把公司的描述放到一个新的数组中,然后输出。

const description = companies.map(
  company =>
    `${company.name} was founded in ${company.founded} and is in the  ${
      company.sector
    } business`
);

description.forEach(d => output(d));

js map function example

一个使用map来迭代我们的数字数组中的所有数字的例子如何。这个例子将把数组中的每个数字设置为2的幂,结果存储在一个新的数组中,然后我们把结果输出给浏览器。

const powerTwo = numbers.map(num => Math.pow(num, 2));

powerTwo.forEach(num => output(num));

javascript map power of 2

所以这些是使用map函数的几个例子。要在React中创建一个列表,你可以使用map函数。


排序

我们可以看一下的另一个高阶函数是排序函数。第一个例子将展示如何将公司从最早的到最新的进行排序。

const sortedCompanies = companies.sort(function(c1, c2) {
  if (c1.founded > c2.founded) {
    return 1;
  } else {
    return -1;
  }
});

sortedCompanies.forEach(c => output(c.name));

javascript sort function in action

你可以用这个更简洁的代码完成同样的结果,它使用了三元操作符,就像这样。

const sortedCompanies = companies.sort((c1, c2) =>
  c1.founded > c2.founded ? 1 : -1
);

sortedCompanies.forEach(c => output(c.name));

将数字数组从最小到最大进行排序如何?可以用这个片段来完成。

const sortInts = numbers.sort((a, b) => a - b);

sortInts.forEach(n => output(n))

;
js sort int low to high


减少

这个 **reduce**函数是一个有趣的函数,它接收一个有许多值的数组,并将其减少到一个输出值。你经常看到这个函数用于把一个数组中的所有值加起来,然后输出这个值。我一直认为用reduce函数做加法有点奇怪,但可惜,事实就是如此。

举例来说。

let numSum = 0;
for (let i = 0; i < numbers.length; i++) {
  numSum += numbers[i];
}

output(numSum);

js reduce higher order function

你可以使用这个更优雅的解决方案来获得同样的结果。

const numSum = numbers.reduce((total, num) => total + num, 0);

现在让我们练习一下在公司对象的数组上使用reduce。这个工作方式有点不同,但概念是一样的。让我们把这些公司总共经营了多少年加起来。

const totalYears = companies.reduce(function(total, company) {
  return total + (2019 - company.founded);
}, 0);

output(totalYears);

js reduce function example

简短的版本也同样好用。

const totalYears = companies.reduce(
  (total, company) => total + (2019 - company.founded),
  0
);

高阶函数的一个有趣的方面是,你可以把它们串联起来,一次完成几个操作。在这里的例子中,我们将把我们的数字分别乘以3,然后只看那些数值大于或等于70的数字,最后从低到高进行排序。

const combined = numbers
  .map(num => num * 3)
  .filter(num => num >= 70)
  .sort((a, b) => a - b);

combined.forEach(c => output(c));

javascript higher order chaining


JavaScript中的高阶函数摘要

在本教程中,我们了解了JavaScript中的一些高阶函数,如filter()、map()、sort()和reduce()。通过使用这些高阶函数,你可以减少你必须编写的 for通过使用这些高阶函数,你可以减少你必须编写的循环,使你能够创建更简洁和优雅的代码。此外,在Vue、React和Angular等流行框架中,经常需要这些类型的函数来转换或过滤数据,所以它们是你工具箱中的一项好技能。