Javascript 零基础教程

JavaScript 高阶函数基础

JavaScript 高阶函数 (Higher-Order Functions) 开启了强大且灵活的编程技术。它们代表了向更抽象、更具表现力的编码风格迈出的重要一步。

理解高阶函数有助于编写高效、可重用和可维护的代码。本章节将向你介绍高阶函数的核心原则,为后续课程中探索实际应用奠定基础。

1. 理解高阶函数

一个高阶函数是指至少满足下列条件之一的函数:

  1. 接受一个或多个函数作为参数。
  2. 返回一个函数作为其结果。

本质上,高阶函数将函数视为一等公民 (First-Class Citizens),这意味着它们可以像其他数据类型(如数字、字符串或对象)一样被操作。

1.1 函数作为参数

高阶函数的一个定义性特征是它们能够接受其他函数作为参数。这允许你将行为作为数据传递,使你的代码更加动态和适应性强。

示例:

function greet(name, formatter) {
  return formatter(name);
}

function uppercaseFormatter(name) {
  return "你好, " + name.toUpperCase() + "!";
}

function lowercaseFormatter(name) {
  return "你好, " + name.toLowerCase() + "!";
}

console.log(greet("Alice", uppercaseFormatter)); // 输出: 你好, ALICE!
console.log(greet("Bob", lowercaseFormatter));   // 输出: 你好, bob!

在这个例子中,greet 是一个高阶函数,因为它接受 formatter 函数作为参数。uppercaseFormatterlowercaseFormatter 是定义特定格式化行为的普通函数。通过将不同的格式化函数传递给 greet,我们可以动态改变问候语的显示方式。

1.2 函数作为返回值

高阶函数也可以返回其他函数作为其结果。这种技术对于创建专用函数或实现函数工厂非常有用。

示例:

function createMultiplier(multiplier) {
  return function(x) {
    return x * multiplier;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 输出: 10
console.log(triple(5)); // 输出: 15

在这里,createMultiplier 是一个返回新函数的高阶函数。返回的函数通过闭包 (Closures)(你在第 4 模块中学到的概念)“记住”了来自外部函数作用域的 multiplier 值。这允许我们创建像 doubletriple 这样的专用函数来执行特定的乘法运算。

1.3 为什么要使用高阶函数?

高阶函数提供了几个优势:

  • 抽象 (Abstraction): 它们允许你抽象出通用的模式和逻辑,使代码更简洁、更易读。
  • 复用性 (Reusability): 它们通过允许你将不同的行为传递给同一个函数来促进代码复用。
  • 灵活性 (Flexibility): 它们通过允许你在运行时动态改变函数的行为来增加代码的灵活性。
  • 模块化 (Modularity): 它们通过将复杂任务分解为更小的独立函数来鼓励模块化设计。

2. 实战示例与演示

2.1 示例 1:事件处理

考虑这样一个场景:你想给按钮元素添加不同的事件监听器。你可以使用高阶函数来封装事件处理逻辑。

function createEventHandler(message) {
  return function(event) {
    console.log(message, event);
  };
}

const button = document.createElement('button');
button.textContent = '点击我';
document.body.appendChild(button);

const clickHandler1 = createEventHandler("按钮被点击了!");
const clickHandler2 = createEventHandler("又一次点击!");

button.addEventListener('click', clickHandler1);
button.addEventListener('click', clickHandler2);

在这个例子中,createEventHandler 返回一个在按钮被点击时记录特定消息的函数。这允许你轻松创建多个具有不同消息的事件处理程序。

2.2 示例 2:自定义排序

JavaScript 的 Array.prototype.sort() 方法可以接受一个比较函数作为参数,这使它成为一个高阶函数。这允许你自定义数组的排序行为。

const numbers = [5, 2, 8, 1, 9, 4];

// 按升序排序
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers); // 输出: [1, 2, 4, 5, 8, 9]

const products = [
  { name: '笔记本电脑', price: 1200 },
  { name: '手机', price: 800 },
  { name: '平板电脑', price: 300 }
];

// 按价格降序排序产品
products.sort(function(a, b) {
  return b.price - a.price;
});
console.log(products);
// 输出:
// [
//   { name: '笔记本电脑', price: 1200 },
//   { name: '手机', price: 800 },
//   { name: '平板电脑', price: 300 }
// ]

在这种情况下,传递给 sort() 的匿名函数定义了比较逻辑。对于数字,a - b 产生升序结果。对于产品数组,比较函数比较产品的价格以进行降序排序。

2.3 示例 3:验证

考虑这样一个场景:你想对用户输入执行不同的验证检查。你可以使用高阶函数来创建可重用的验证规则。

function createValidator(validationFn, errorMessage) {
  return function(input) {
    if (!validationFn(input)) {
      return errorMessage;
    }
    return null; // 无错误
  };
}

const isRequired = createValidator(
  (input) => input !== '',
  '此字段为必填项。'
);

const isEmail = createValidator(
  (input) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input),
  '无效的电子邮件地址。'
);

console.log(isRequired('')); // 输出: 此字段为必填项。
console.log(isRequired('John')); // 输出: null
console.log(isEmail('test')); // 输出: 无效的电子邮件地址。
console.log(isEmail('test@example.com')); // 输出: null

createValidator 函数根据提供的验证规则和错误消息返回一个验证器函数。