原文:Higher Order Functions: Using Filter, Map and Reduce for More Maintainable Code
做者:Guido Schmitz
译者:JeLewinejavascript
高阶函数能够帮助你加强你的JavaScript,让你的代码更具备声明性。简单来讲,就是简单,简练,可读。java
知道何时和怎样使用高阶函数是相当重要的。它们可让你的代码更容易理解和具备更好的可维护性。它们也可让你很轻松的进行函数间的组合。咱们叫它复合函数,不过我不会在这里进行详细的介绍。在本文中,我将介绍JavaScript中三个最经常使用的高阶函数:.filter()
,.map()
,.reduce
。数组
想象一下你正在编写一段代码:有一个写满不一样人信息的列表,不过你想要过滤出一个大于等于18岁人的列表。函数
咱们的列表看起来就像下面这样:ui
const people = [ { name: ‘John Doe’, age: 16 }, { name: ‘Thomas Calls’, age: 19 }, { name: ‘Liam Smith’, age: 20 }, { name: ‘Jessy Pinkman’, age: 18 }, ];
咱们先来看看第一个高阶函数是如何筛选出大于等于18岁人的栗子。为了简洁,我将使用ES6标准中的箭头函数。这是一种很是简洁的定义函数的方式,可让咱们没必要再写function
和return
,以及一些括号、大括号和分号。code
const peopleAbove18 = (collection) => { const results = []; for (let i = 0; i < collection.length; i++) { const person = collection[i]; if (person.age >= 18) { results.push(person); } } return results; };
那如今若是咱们想要筛选出18~20岁之间的人呢?ip
const peopleBetween18And20 = (collection) => { const results = []; for (let i = 0; i < collection.length; i++) { const person = collection[i]; if (person.age >= 18 && person.age <= 20) { results.push(person); } } return results; };
你可能已经意识到了这里有许多重复的代码。咱们能够抽象出一个通用的解决方案。这两个函数有一些共同点。它们都在一个列表中进行迭代,而且在给定的条件下进行过滤。rem
"高阶函数是一个将一个或多个函数做为参数的函数"——ClojureBridgeget
咱们能够经过使用更具声明性的.filter()
方法来改进咱们以前的函数。原型
const peopleAbove18 = (collection) => { return collection .filter((person) => person.age >= 18); }
太棒了!咱们经过使用高阶函数减小了许多额外的代码。同时也让咱们的代码更具可读性。咱们不在意如何过滤东西,咱们只是但愿它被过滤。这篇文章稍后会介绍组合函数。
让咱们拿着刚刚的人员名单和一个其中喜欢喝咖啡的人员名单。
const coffeeLovers = [‘John Doe’, ‘Liam Smith’, ‘Jessy Pinkman’];
用命令式的实现方式就像下面这样:
const addCoffeeLoverValue = (collection) => { const results = []; for (let i = 0; i < collection.length; i++) { const person = collection[i]; if (coffeeLovers.includes(person.name)) { person.coffeeLover = true; } else { person.coffeeLover = false; } results.push(person); } return results; };
咱们能够利用.map()
来让代码更具备声明性:
const incrementAge = (collection) => { return collection.map((person) => { person.coffeeLover = coffeeLovers.includes(person.name); return person; }); };
再说一遍,.map()
是一个高阶函数。它容许咱们将一个函数做为参数传递。
我敢打赌,当你知道何时和怎样使用它的时候,你会喜欢上这个函数。.reduce()
很酷,上面提到的的大部分函数均可以经过它来实现。
让咱们先举一个简单的栗子。咱们想计算全部人年龄的和。固然了,咱们仍是会首先看看如何用命令式的方式实现。它基本上就是经过循环来增长总年龄变量。
const sumAge = (collection) => { let num = 0; collection.forEach((person) => { num += person.age; }); return num; }
接下来是使用.reduce()
的声明式方法:
const sumAge = (collection) => collection.reduce((sum, person) => { return sum + person.age; }, 0);
咱们甚至可使用.reduce()
来建立咱们本身的.map()
和.filter()
。
const map = (collection, fn) => { return collection.reduce((acc, item) => { return acc.concat(fn(item)); }, []); } const filter = (collection, fn) => { return collection.reduce((acc, item) => { if (fn(item)) { return acc.concat(item); } return acc; }, []); }
一开始这一起可能比较难理解。不过,.reduce()
作的基本上就是以一个集合和一个定义了初始值的变量开始。而后,遍历该集合并将值添加到变量中去。
太好了,这些函数咱们都有了。并且很重要的一点是,他们都存在于JavaScript的数组原型上。这意味着咱们能够同时使用它们。这可让咱们轻松建立各类可复用的函数,减小编写某些功能所须要的代码量。
咱们已经讨论过了如何利用.filter()
来过滤出大于等于18岁的人;利用.map()
来添加coffeeLover
属性;经过.reduce()
来计算全部人年龄的和。如今,咱们写一点代码将这三个步骤合并起来。
const people = [ { name: ‘John Doe’, age: 16 }, { name: ‘Thomas Calls’, age: 19 }, { name: ‘Liam Smith’, age: 20 }, { name: ‘Jessy Pinkman’, age: 18 }, ]; const coffeeLovers = [‘John Doe’, ‘Liam Smith’, ‘Jessy Pinkman’]; const ageAbove18 = (person) => person.age >= 18; const addCoffeeLoverProperty = (person) => { person.coffeeLover = coffeeLovers.includes(person.name); return person; } const ageReducer = (sum, person) => { return sum + person.age; }, 0); const coffeeLoversAbove18 = people .filter(ageAbove18) .map(addCoffeeLoverProperty); const totalAgeOfCoffeeLoversAbove18 = coffeeLoversAbove18 .reduce(ageReducer); const totalAge = people .reduce(ageReducer);
若是你用命令式方法的话,你最后会写一堆重复代码。
经过.map()
,.reduce()
和.filter()
来建立函数的思惟将会极大的提升你的代码质量。并且能够增长可读性。你根本没必要在乎函数内到底发生了什么,它很是容易理解。