Skip to content

高级高阶函数:函数的元编程艺术

超越基础的高阶函数

如果说基础的高阶函数如 mapfilterreduce 是函数式编程的工具箱, 那么高级高阶函数就是构建工具的工具——它们不仅处理数据, 更是处理函数本身。

在 JavaScript 的世界里, 函数是一等公民。这意味着函数不仅可以作为参数传递、作为返回值, 还可以被存储、修改、组合。高级高阶函数正是充分利用这一特性, 创造出强大而优雅的抽象。

函数装饰器

装饰器(Decorator)是一种特殊的高阶函数, 它接收一个函数并返回一个增强版本的函数, 而不改变原函数的核心行为。

1. 日志装饰器

javascript
// 基础日志装饰器
function withLogging(fn, label = fn.name) {
  return function (...args) {
    console.log(`[${label}] 调用, 参数:`, args);
    const result = fn(...args);
    console.log(`[${label}] 返回:`, result);
    return result;
  };
}

// 使用装饰器
function add(a, b) {
  return a + b;
}

const addWithLogging = withLogging(add, "ADD");

addWithLogging(5, 3);
// [ADD] 调用, 参数: [5, 3]
// [ADD] 返回: 8
// => 8

2. 性能计时装饰器

javascript
function withTiming(fn, label = fn.name) {
  return function (...args) {
    const start = performance.now();
    const result = fn(...args);
    const end = performance.now();

    console.log(`[${label}] 执行时间: ${(end - start).toFixed(2)}ms`);
    return result;
  };
}

// 测量函数性能
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

const timedFib = withTiming(fibonacci, "Fibonacci");

console.log(timedFib(30));
// [Fibonacci] 执行时间: 12.34ms
// => 832040

3. 错误处理装饰器

javascript
function withErrorHandling(fn, onError = console.error) {
  return function (...args) {
    try {
      return fn(...args);
    } catch (error) {
      onError(`函数 ${fn.name} 执行出错:`, error.message);
      return null;
    }
  };
}

// 使用示例
function parseJSON(jsonString) {
  return JSON.parse(jsonString);
}

const safeParseJSON = withErrorHandling(parseJSON);

console.log(safeParseJSON('{"name":"John"}')); // { name: 'John' }
console.log(safeParseJSON("{invalid}")); // null (错误被捕获)

4. 重试装饰器

javascript
function withRetry(fn, maxAttempts = 3, delay = 1000) {
  return async function (...args) {
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        return await fn(...args);
      } catch (error) {
        if (attempt === maxAttempts) {
          throw error;
        }

        console.log(`尝试 ${attempt} 失败, ${delay}ms 后重试...`);
        await new Promise((resolve) => setTimeout(resolve, delay));
      }
    }
  };
}

// 模拟不稳定的 API 调用
async function fetchData(url) {
  if (Math.random() < 0.7) {
    // 70% 失败率
    throw new Error("网络错误");
  }
  return { data: `来自 ${url} 的数据` };
}

const reliableFetch = withRetry(fetchData, 3, 500);

reliableFetch("https://api.example.com/data")
  .then((result) => console.log("成功:", result))
  .catch((error) => console.log("最终失败:", error.message));

5. 组合多个装饰器

javascript
// 组合装饰器
function compose(...decorators) {
  return function (fn) {
    return decorators.reduceRight((decorated, decorator) => {
      return decorator(decorated);
    }, fn);
  };
}

// 创建一个完全装饰的函数
function expensiveCalculation(n) {
  let result = 0;
  for (let i = 0; i < n; i++) {
    result += Math.sqrt(i);
  }
  return result;
}

const fullyDecorated = compose(
  withLogging,
  withTiming,
  withErrorHandling
)(expensiveCalculation);

fullyDecorated(1000000);
// [expensiveCalculation] 调用, 参数: [1000000]
// [expensiveCalculation] 执行时间: 25.67ms
// [expensiveCalculation] 返回: 666666166.6667

偏函数应用

偏函数应用(Partial Application)是预先填充函数的部分参数, 创建一个参数更少的新函数。

1. 基础偏函数

javascript
// 通用的偏函数应用
function partial(fn, ...presetArgs) {
  return function (...laterArgs) {
    return fn(...presetArgs, ...laterArgs);
  };
}

// 示例: 数学运算
function multiply(a, b, c) {
  return a * b * c;
}

const multiplyByTwo = partial(multiply, 2);
console.log(multiplyByTwo(3, 4)); // 2 * 3 * 4 = 24

const multiplyByTwoAndThree = partial(multiply, 2, 3);
console.log(multiplyByTwoAndThree(4)); // 2 * 3 * 4 = 24

2. 实际应用: HTTP 请求

javascript
// 通用的 fetch 封装
async function request(baseURL, headers, method, endpoint, body) {
  const url = `${baseURL}${endpoint}`;
  const options = {
    method,
    headers: { ...headers, "Content-Type": "application/json" },
    ...(body && { body: JSON.stringify(body) }),
  };

  const response = await fetch(url, options);
  return response.json();
}

// 创建 API 客户端
const apiRequest = partial(request, "https://api.example.com", {
  Authorization: "Bearer token123",
});

const get = partial(apiRequest, "GET");
const post = partial(apiRequest, "POST");
const put = partial(apiRequest, "PUT");
const del = partial(apiRequest, "DELETE");

// 使用
get("/users"); // GET /users
post("/users", { name: "John" }); // POST /users
put("/users/1", { name: "Jane" }); // PUT /users/1
del("/users/1"); // DELETE /users/1

3. 配置式偏函数

javascript
// 数据验证器
function createValidator(rules, errorMessages, data) {
  const errors = [];

  for (const [field, rule] of Object.entries(rules)) {
    if (!rule(data[field])) {
      errors.push({
        field,
        message: errorMessages[field] || `${field} 验证失败`,
      });
    }
  }

  return {
    isValid: errors.length === 0,
    errors,
  };
}

// 预设验证规则和错误信息
const validateUser = partial(
  createValidator,
  {
    name: (value) => value && value.length >= 2,
    email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
    age: (value) => value >= 18 && value <= 100,
  },
  {
    name: "姓名至少需要2个字符",
    email: "请输入有效的邮箱地址",
    age: "年龄必须在 18-100 之间",
  }
);

// 使用
console.log(validateUser({ name: "J", email: "invalid", age: 15 }));
// { isValid: false, errors: [...] }

console.log(
  validateUser({
    name: "John",
    email: "[email protected]",
    age: 25,
  })
);
// { isValid: true, errors: [] }

函数组合器

组合器(Combinator)是操作函数的高阶函数, 用于构建复杂的数据处理管道。

1. Compose 和 Pipe

javascript
// compose: 从右到左执行
const compose =
  (...fns) =>
  (value) =>
    fns.reduceRight((acc, fn) => fn(acc), value);

// pipe: 从左到右执行
const pipe =
  (...fns) =>
  (value) =>
    fns.reduce((acc, fn) => fn(acc), value);

// 数据转换函数
const trim = (str) => str.trim();
const toLowerCase = (str) => str.toLowerCase();
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
const addExclamation = (str) => str + "!";

// 使用 pipe (更直观)
const formatGreeting = pipe(trim, toLowerCase, capitalize, addExclamation);

console.log(formatGreeting("  HELLO  ")); // "Hello!"

2. 异步组合

javascript
// 异步 pipe
const asyncPipe =
  (...fns) =>
  (value) =>
    fns.reduce(async (acc, fn) => fn(await acc), value);

// 异步操作
const fetchUser = async (id) => {
  await new Promise((resolve) => setTimeout(resolve, 100));
  return { id, name: "John", age: 25 };
};

const enrichWithPosts = async (user) => {
  await new Promise((resolve) => setTimeout(resolve, 100));
  return { ...user, posts: ["Post 1", "Post 2"] };
};

const addTimestamp = async (user) => {
  return { ...user, fetchedAt: new Date() };
};

// 组合异步操作
const getUserWithData = asyncPipe(fetchUser, enrichWithPosts, addTimestamp);

getUserWithData(1).then(console.log);
// { id: 1, name: 'John', age: 25, posts: [...], fetchedAt: ... }

3. 条件组合

javascript
// 条件执行组合器
const when = (predicate, fn) => (value) => predicate(value) ? fn(value) : value;

const unless = (predicate, fn) => when((value) => !predicate(value), fn);

// 使用示例
const processNumber = pipe(
  when((n) => n < 0, Math.abs), // 转为正数
  when(
    (n) => n > 100,
    (n) => 100
  ), // 限制最大值
  unless(Number.isInteger, Math.floor) // 取整
);

console.log(processNumber(-50)); // 50
console.log(processNumber(150)); // 100
console.log(processNumber(45.7)); // 45
console.log(processNumber(30)); // 30

4. Map 组合器

javascript
// map 组合器 - 将函数应用到数组的每个元素
const map = (fn) => (array) => array.map(fn);

// 组合多个映射操作
const processUsers = pipe(
  map((user) => ({ ...user, name: user.name.toUpperCase() })),
  map((user) => ({ ...user, isAdult: user.age >= 18 })),
  map((user) => ({
    ...user,
    category: user.age < 18 ? "youth" : user.age < 60 ? "adult" : "senior",
  }))
);

const users = [
  { name: "john", age: 15 },
  { name: "jane", age: 25 },
  { name: "bob", age: 65 },
];

console.log(processUsers(users));

记忆化装饰器

记忆化(Memoization)通过缓存函数结果来优化性能:

javascript
function memoize(fn) {
  const cache = new Map();

  return function (...args) {
    const key = JSON.stringify(args);

    if (cache.has(key)) {
      console.log("从缓存返回:", key);
      return cache.get(key);
    }

    console.log("计算新结果:", key);
    const result = fn(...args);
    cache.set(key, result);

    return result;
  };
}

// 斐波那契数列 - 未优化
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// 记忆化版本
const memoizedFib = memoize(fibonacci);

console.time("First call");
console.log(memoizedFib(40));
console.timeEnd("First call");

console.time("Second call");
console.log(memoizedFib(40));
console.timeEnd("Second call");
// Second call 几乎瞬间完成

高级记忆化 - 支持自定义缓存策略:

javascript
function memoizeAdvanced(fn, options = {}) {
  const {
    maxSize = Infinity,
    maxAge = Infinity,
    keyGenerator = JSON.stringify,
  } = options;

  const cache = new Map();
  const timestamps = new Map();

  return function (...args) {
    const key = keyGenerator(args);
    const now = Date.now();

    // 检查缓存
    if (cache.has(key)) {
      const timestamp = timestamps.get(key);

      // 检查是否过期
      if (now - timestamp < maxAge) {
        return cache.get(key);
      }

      // 过期则删除
      cache.delete(key);
      timestamps.delete(key);
    }

    // 计算结果
    const result = fn(...args);

    // 检查缓存大小限制
    if (cache.size >= maxSize) {
      // 删除最早的条目
      const firstKey = cache.keys().next().value;
      cache.delete(firstKey);
      timestamps.delete(firstKey);
    }

    // 存入缓存
    cache.set(key, result);
    timestamps.set(key, now);

    return result;
  };
}

// 使用示例: API 调用缓存
const fetchUserData = memoizeAdvanced(
  async (userId) => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
  {
    maxSize: 100, // 最多缓存 100 个用户
    maxAge: 60000, // 缓存 1 分钟
    keyGenerator: ([userId]) => `user_${userId}`,
  }
);

函数工厂

函数工厂是返回配置化函数的高阶函数:

javascript
// 创建验证器工厂
function createValidator(type) {
  const validators = {
    email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
    phone: (value) => /^\d{10,11}$/.test(value),
    url: (value) => /^https?:\/\/.+/.test(value),
    required: (value) => value != null && value !== "",
    minLength: (min) => (value) => value.length >= min,
    maxLength: (max) => (value) => value.length <= max,
    range: (min, max) => (value) => value >= min && value <= max,
  };

  return validators[type];
}

// 使用
const isEmail = createValidator("email");
const isPhone = createValidator("phone");
const isMinLength8 = createValidator("minLength")(8);

console.log(isEmail("[email protected]")); // true
console.log(isPhone("1234567890")); // true
console.log(isMinLength8("password123")); // true

创建数据转换器工厂:

javascript
function createTransformer(type) {
  const transformers = {
    trim: (str) => str.trim(),
    uppercase: (str) => str.toUpperCase(),
    lowercase: (str) => str.toLowerCase(),
    capitalize: (str) => str.charAt(0).toUpperCase() + str.slice(1),
    slugify: (str) =>
      str
        .toLowerCase()
        .replace(/[^\w\s-]/g, "")
        .replace(/\s+/g, "-"),
    truncate: (maxLength) => (str) =>
      str.length > maxLength ? str.slice(0, maxLength) + "..." : str,
    padStart:
      (length, char = " ") =>
      (str) =>
        str.padStart(length, char),
    padEnd:
      (length, char = " ") =>
      (str) =>
        str.padEnd(length, char),
  };

  return transformers[type];
}

// 组合转换器
const processTitle = pipe(
  createTransformer("trim"),
  createTransformer("capitalize"),
  createTransformer("truncate")(50)
);

console.log(
  processTitle("  this is a very long title that needs processing  ")
);

实战应用: 中间件系统

javascript
// Express 风格的中间件系统
class MiddlewareEngine {
  constructor() {
    this.middlewares = [];
  }

  use(fn) {
    this.middlewares.push(fn);
    return this;
  }

  async execute(context) {
    let index = 0;

    const next = async () => {
      if (index >= this.middlewares.length) {
        return;
      }

      const middleware = this.middlewares[index++];
      await middleware(context, next);
    };

    await next();
    return context;
  }
}

// 使用示例
const app = new MiddlewareEngine();

// 日志中间件
app.use(async (ctx, next) => {
  console.log("-> 请求开始:", ctx.path);
  await next();
  console.log("<- 请求结束:", ctx.path);
});

// 认证中间件
app.use(async (ctx, next) => {
  if (!ctx.user) {
    ctx.error = "未认证";
    return;
  }
  await next();
});

// 业务逻辑
app.use(async (ctx, next) => {
  ctx.result = `处理 ${ctx.path}`;
  await next();
});

// 执行
app
  .execute({
    path: "/api/users",
    user: { id: 1, name: "John" },
  })
  .then((result) => {
    console.log("最终结果:", result);
  });

小结

高级高阶函数是函数式编程中的强大工具, 它们让我们能够:

  1. 装饰器模式: 增强函数功能而不修改原函数
  2. 偏函数应用: 创建参数预设的函数变体
  3. 函数组合: 构建复杂的数据处理管道
  4. 记忆化: 通过缓存优化性能
  5. 函数工厂: 生成配置化的函数

这些技术不仅让代码更简洁优雅, 还提供了强大的抽象能力。掌握高级高阶函数, 能让你用更少的代码完成更多的工作, 写出更易维护和测试的程序。

高阶函数的关键是将函数视为数据——它们可以被创建、传递、组合和转换。这种思维方式会彻底改变你构建程序的方式。