WEB程序员笔记

一个前端开发工程师的个人博客

什么是高阶函数?

您可能在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;
}

那么,这到底是怎么回事?这是一个演练:

  1. 我们指定函数的第一个参数为对象(obj)。然后,我们使用rest运算符(...tests)表示任何其他参数都将在tests数组中。
  2. 我们使用for循环来遍历tests数组,数组是一个函数数组(这是高阶部分!)。
  3. 我们传递objtests数组中的每个项目。如果该函数求值false,我们知道obj是无效的并立即返回false
  4. 如果我们遍历整个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;
  };
}

让我们看看如何在再次验证newUser1newUser2对象时为我们提供更一致的界面:

const userValidator = createValidator(
  oldEnough,
  passwordLongEnough,
  agreeToTerms
);

userValidator(newUser1); // true
userValidator(newUser2); // false

太棒了!通过使用我们createValidator的高阶函数,我们不可能无意间对我们的不同对象使用不同的验证标准。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注