高阶函数 JavaScript JavaScript 中的高阶函数
介绍
在 JavaScript 中,函数是值(一等公民)。这意味着它们可以赋值给变量或作为值传递。
let random = function(){
return Math.random()
}
let giveMeRandom = random // assigning random to a variable
仅仅掌握了这一点,我们就可以用这种语言编写函数式编程了。在函数式编程中,我们大量使用高阶函数。
高阶函数?
高阶函数是将其他函数作为参数或返回函数作为结果的函数。
接受其他函数作为参数的函数通常被称为回调函数,因为它会被高阶函数回调。这是 JavaScript 中经常使用的概念。
例如,数组上的map函数就是一个高阶函数。map函数接受一个函数作为参数。
const double = n => n * 2
[1, 2, 3, 4].map(double) // [ 2, 4, 6, 8 ]
或者,使用匿名函数:
[1, 2, 3, 4].map(function(n){
return n * 2
}) // [ 2, 4, 6, 8 ]
map函数是该语言内置的众多高阶函数之一。sort 、reduce 、 filter 、 forEach是该语言内置的高阶函数的其他示例。
高阶函数可以让你编写更简洁、更优雅的代码。让我们看看上面的代码如果没有这种抽象会是什么样子。让我们用一个循环替换map函数:
let array = [1, 2, 3, 4]
let newArray = []
for(let i = 0; n < array.length; i++) {
newArray[i] = array[i] * 2
}
newArray // [ 2, 4, 6, 8 ]
构图的力量
当我们可以使用高阶函数时,其最大的优势之一就是组合。
我们可以创建一些较小的函数,只处理单一逻辑。然后,我们再使用不同的小函数来组合出更复杂的函数。
这种技术减少了错误并使我们的代码更易于阅读和理解。
通过学习使用高阶函数,您可以开始编写更好的代码。
例子
让我们举个例子。假设我们有一个班级的成绩列表。我们班有 5 个女生,5 个男生,每个人的成绩都在 0 到 20 之间。
var grades = [
{name: 'John', grade: 8, sex: 'M'},
{name: 'Sarah', grade: 12, sex: 'F'},
{name: 'Bob', grade: 16, sex: 'M'},
{name: 'Johnny', grade: 2, sex: 'M'},
{name: 'Ethan', grade: 4, sex: 'M'},
{name: 'Paula', grade: 18, sex: 'F'},
{name: 'Donald', grade: 5, sex: 'M'},
{name: 'Jennifer', grade: 13, sex: 'F'},
{name: 'Courtney', grade: 15, sex: 'F'},
{name: 'Jane', grade: 9, sex: 'F'}
]
我想知道一些关于此的事情:
- 这个教室的平均成绩
- 男生的平均成绩
- 女生的平均成绩
- 男孩们中音调最高的
- 女孩们中最高的音符
我们将尝试使用高阶函数来编写一个简单易读的程序。让我们从编写一些可以协同工作的简单函数开始:
let isBoy = student => student.sex === 'M'
let isGirl = student => student.sex === 'F'
let getBoys = grades => (
grades.filter(isBoy)
)
let getGirls = grades => (
grades.filter(isGirl)
)
let average = grades => (
grades.reduce((acc, curr) => (
acc + curr.grade
), 0) / grades.length
)
let maxGrade = grades => (
Math.max(...grades.map(student => student.grade))
)
let minGrade = grades => (
Math.min(...grades.map(student => student.grade))
)
我写了 7 个函数,每个函数都有一项任务,而且只有一项任务。
isBoy和isGirl负责检查一个学生是男孩还是女孩。
getBoys和getGirls负责从教室里取出所有的男孩或女孩。
maxGrade和minGrade负责获取某些数据中的最高和最低等级。
最后,平均值负责计算一些数据的平均等级。
请注意,average函数还不知道它要处理的数据类型。这就是组合的美妙之处。我们可以在不同的地方复用我们的代码。我可以直接把这个函数和其他函数连接起来。
现在,我们已经有了编写高阶函数所需的一切:
let classroomAverage = average(grades) // 10.2
let boysAverage = average(getBoys(grades)) // 7
let girlsAverage = average(getGirls(grades)) // 13.4
let highestGrade = maxGrade(grades) // 18
let lowestGrade = minGrade(grades) // 2
let highestBoysGrade = maxGrade(getBoys(grades)) // 16
let lowestBoysGrade = minGrade(getBoys(grades)) // 2
let highestGirlsGrade = maxGrade(getGirls(grades)) // 18
let lowestGirlsGrade = minGrade(getGirls(grades)) // 9
注意,外部函数(例如平均值)总是将内部函数的输出作为输入。因此,组合的唯一条件是确保输出和输入匹配。
而且由于每个函数只负责一件事,这使得我们的代码更容易调试和测试。