您可能在JavaScript世界中听到的一个术语是“高阶函数”。今天,我们将探讨成为高阶函数的含义,并查看JavaScript中的一些示例!
定义
根据定义,高阶函数是将函数作为参数或返回函数的函数。
如果您不熟悉将函数作为第一类对象[1],那么您可能会感到惊讶。但是,它确实非常强大!
一些简单的例子
让我们看几个简单的示例:一个用于将函数作为参数的函数,另一个用于返回函数的函数。
以函数为参数
让我们创建一个相对无用的函数evaluatesToFive
,该函数带有两个参数:第一个参数是数字,第二个参数是函数。在evaluatesToFive
函数内部,我们将检查将数字传递给函数的结果是否为5。
function evaluatesToFive(num, fn) {
return fn(num) === 5;
}
我们可以检查一下它的作用:
function divideByTwo(num) {
return num / 2;
}
evaluatesToFive(10, divideByTwo);
// true
evaluatesToFive(20, divideByTwo);
// false
有点没用,但是我们可以做到这一点很酷!
返回函数
在下一个示例中,我们将创建一个返回函数的函数。我们的函数创建函数将称为multiplyBy
。它将一个数字作为参数,并返回一个新函数,该函数将其输入乘以该数字。
function multiplyBy(num1) {
return function(num2) {
return num1 * num2;
};
}
现在,我们将通过创建几个乘法器函数来看到它的使用:
const multiplyByThree = multiplyBy(3);
const multiplyByFive = multiplyBy(5);
multipyByThree(10); // 30
multiplyByFive(10); // 50
再说一次,以目前的形式不是超级有用,但是无论如何都很酷。
一个更复杂且可能有用的示例
实际使用的高阶函数的一个更有用的示例是对象验证器。基本思想是一个函数,该函数将一个对象作为参数,然后true
接受必须视为该对象有效的任何数量的函数。
在此示例中,我们将处理一个newUser
对象并尝试确定是否应允许它们注册我们的应用程序。用户必须满足以下条件:
- 必须年满18岁
- 密码必须至少8个字符长
- 必须同意服务条款
理想newUser
对象看起来像这样:
const newUser = {
age: 24,
password: 'some long password',
agreeToTerms: true,
};
基于这些知识,我们可以创建一些测试函数,这些函数true
在满足我们期望的条件时返回,false
否则返回。
function oldEnough(user) {
return user.age >= 18;
}
function passwordLongEnough(user) {
return user.password.length >= 8;
}
function agreeToTerms(user) {
return user.agreeToTerms === true;
}
现在,我们可以创建一个接受任意数量参数的函数。第一个参数将是我们要验证的对象,其余参数将是用于测试对象的测试函数。
function validate(obj, ...tests) {
for (let i = 0; i < tests.length; i++) {
if (tests[i](obj) === false) {
return false;
}
}
return true;
}
那么,这到底是怎么回事?这是一个演练:
- 我们指定函数的第一个参数为对象(
obj
)。然后,我们使用rest运算符(...tests
)表示任何其他参数都将在tests
数组中。 - 我们使用
for
循环来遍历tests
数组,数组是一个函数数组(这是高阶部分!)。 - 我们传递
obj
给tests
数组中的每个项目。如果该函数求值false
,我们知道obj
是无效的并立即返回false
。 - 如果我们遍历整个
tests
数组而不返回false
,则我们的对象有效,然后返回true
。
看到它在行动
现在,我们通过验证几个潜在的新用户对象来使用我们的验证高阶函数:
const newUser1 = {
age: 40,
password: 'tncy4ty49r2mrx',
agreeToTerms: true,
};
validate(newUser1, oldEnough, passwordLongEnough, agreeToTerms);
// true
const newUser2 = {
age: 40,
password: 'short',
agreeToTerms: true,
};
validate(newUser2, oldEnough, passwordLongEnough, agreeToTerms);
// false
我们终于得到它了!newUser1
被正确视为有效,但newUser2
由于其password
太短而被检测为无效。
潜在的改进:创建验证器的功能
优点:如果我们将validate
功能应用到多个用户,最好不要一次又一次地重复指定相同的测试。相反,我们可以有一个createValidator
返回对象验证器的函数。在这种情况下,我们将创建一个userValidator
,将相同的测试功能应用于我们尝试验证的任何用户。
function createValidator(...tests) {
return function(obj) {
for (let i = 0; i < tests.length; i++) {
if (tests[i](obj) === false) {
return false;
}
}
return true;
};
}
让我们看看如何在再次验证newUser1
和newUser2
对象时为我们提供更一致的界面:
const userValidator = createValidator(
oldEnough,
passwordLongEnough,
agreeToTerms
);
userValidator(newUser1); // true
userValidator(newUser2); // false
太棒了!通过使用我们createValidator
的高阶函数,我们不可能无意间对我们的不同对象使用不同的验证标准。