领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

前端面试-js高阶函数的介绍和使用

nixiaole 2025-04-27 15:31:39 知识剖析 3 ℃

一、什么是高阶函数?

高阶函数满足以下任一条件:

  1. 接受函数作为参数
  2. 返回一个新的函数

高阶函数的核心思想是将函数视为“一等公民”,像操作数据一样操作函数。

二、高阶函数的常见用途

1. 数组方法(接受函数作为参数)

JavaScript 数组的许多内置方法都是高阶函数,典型例子包括:

  • map():对数组每个元素执行操作,返回新数组。
const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2); // [2, 4, 6]

filter():筛选符合条件的元素。

const evens = numbers.filter(x => x % 2 === 0); // [2]

reduce():将数组元素累积为单个值。

const sum = numbers.reduce((acc, x) => acc + x, 0); // 6

find()some():查找元素或判断条件。

const firstEven = numbers.find(x => x % 2 === 0); // 2
const hasEven = numbers.some(x => x % 2 === 0); // true

高阶用法

一、函数组合与管道(Function Composition & Piping)

1.组合多个函数

将多个函数串联为一个新函数,实现数据处理流水线:

const compose = (...fns) => (initialValue) =>
  fns.reduceRight((acc, fn) => fn(acc), initialValue);

// 示例:字符串处理
const toUpperCase = str => str.toUpperCase();
const addExclamation = str => str + "!";
const reverse = str => str.split('').reverse().join('');

const processString = compose(reverse, addExclamation, toUpperCase);
console.log(processString("hello")); // "OLLEH! -> !OLLEH"

2.管道(从左到右执行)

与 compose 类似,但执行顺序相反:

const pipe = (...fns) => (initialValue) =>
  fns.reduce((acc, fn) => fn(acc), initialValue);

const processStringPipe = pipe(toUpperCase, addExclamation, reverse);
console.log(processStringPipe("hello")); // "HELLO! -> !OLLEH"

二、高阶函数的抽象模式

1.中间件模式(Middleware Pattern)

用于 Express、Redux 等框架的中间件系统:

const createMiddleware = (...middlewares) => {
  return (initialHandler) => {
    return middlewares.reduceRight(
      (next, middleware) => middleware(next),
      initialHandler
    );
  };
};

// 中间件示例
const logger = (next) => (action) => {
  console.log("Action:", action);
  return next(action);
};
const validator = (next) => (action) => {
  if (!action.type) throw new Error("Invalid action");
  return next(action);
};

// 组合中间件
const finalHandler = (action) => console.log("Handling:", action);
const applyMiddleware = createMiddleware(logger, validator);
const enhancedHandler = applyMiddleware(finalHandler);

enhancedHandler({ type: "TEST" }); // 输出日志并验证

2.依赖注入(Dependency Injection)

通过高阶函数实现解耦:

const createService = (dependencies) => (config) => {
  return {
    log: () => dependencies.logger.log(config.message)
  };
};

// 使用
const serviceFactory = createService({ logger: console });
const service = serviceFactory({ message: "Hello" });
service.log(); // 输出 "Hello"

三、高阶函数与异步编程

1.Promise 链的抽象

用高阶函数封装重复的异步逻辑:

const withRetry = (fn, retries = 3) => async (...args) => {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn(...args);
    } catch (error) {
      if (i === retries - 1) throw error;
    }
  }
};

// 使用
const fetchData = () => fetch("https://api.example.com/data");
const fetchWithRetry = withRetry(fetchData, 2);
fetchWithRetry().then(/* ... */);

2.异步函数组合

处理异步函数的流水线:

const asyncPipe = (...fns) => async (initial) => {
  return fns.reduce(async (accPromise, fn) => {
    const acc = await accPromise;
    return fn(acc);
  }, initial);
};

// 示例
const fetchUser = async (id) => ({ id, name: "John" });
const fetchPosts = async (user) => [{ userId: user.id, post: "Hello" }];
const processData = asyncPipe(fetchUser, fetchPosts);

processData(1).then(console.log); // 输出用户关联的帖子

四、惰性求值与高阶函数

通过高阶函数实现延迟计算:

const lazyMap = (fn) => function* (iterable) {
  for (const item of iterable) {
    yield fn(item);
  }
};

const lazyFilter = (predicate) => function* (iterable) {
  for (const item of iterable) {
    if (predicate(item)) yield item;
  }
};

// 使用生成器实现惰性计算
const numbers = [1, 2, 3, 4, 5];
const mapped = lazyMap(x => x * 2)(numbers);
const filtered = lazyFilter(x => x > 5)(mapped);

console.log([...filtered]); // [6, 8, 10]

五、状态管理与高阶函数

1.状态转换器

封装状态变更逻辑:

const withState = (initialState) => (reducer) => {
  let state = initialState;
  return (...args) => {
    state = reducer(state, ...args);
    return state;
  };
};

// 示例:计数器
const counterReducer = (state, action) => {
  switch (action) {
    case "INC": return state + 1;
    case "DEC": return state - 1;
    default: return state;
  }
};

const counter = withState(0)(counterReducer);
console.log(counter("INC")); // 1
console.log(counter("INC")); // 2

2.Redux 风格的 Store

模仿 Redux 的核心逻辑:

const createStore = (reducer, initialState) => {
  let state = initialState;
  const listeners = [];
  return {
    getState: () => state,
    dispatch: (action) => {
      state = reducer(state, action);
      listeners.forEach(listener => listener());
    },
    subscribe: (listener) => {
      listeners.push(listener);
      return () => listeners.splice(listeners.indexOf(listener), 1);
    }
  };
};

六、高级柯里化与部分应用

1.动态柯里化

支持任意数量参数的柯里化:

const curry = (fn) => {
  const curried = (...args) =>
    args.length >= fn.length
      ? fn(...args)
      : (...moreArgs) => curried(...args, ...moreArgs);
  return curried;
};

// 使用
const add = curry((a, b, c) => a + b + c);
console.log(add(1)(2)(3)); // 6
console.log(add(1, 2)(3)); // 6

2.占位符参数

实现灵活的部分应用(类似 Lodash 的 _):

const _ = Symbol("placeholder");
const partial = (fn, ...args) => (...newArgs) => {
  const finalArgs = args.map(arg => arg === _ ? newArgs.shift() : arg);
  return fn(...finalArgs, ...newArgs);
};

// 示例
const greet = (greeting, name) => `${greeting}, ${name}!`;
const sayHello = partial(greet, "Hello", _);
console.log(sayHello("Alice")); // "Hello, Alice!"

七、函数式编程库的底层实现

1.Functor(函子)

封装值并提供 map 方法:

class Functor {
  constructor(value) {
    this.value = value;
  }
  map(fn) {
    return new Functor(fn(this.value));
  }
}

// 使用
new Functor(2)
  .map(x => x * 3)
  .map(x => x + 1)
  .value; // 7

2.Monad(单子)

处理副作用或嵌套结构(如 Promise):

class Maybe {
  constructor(value) {
    this.value = value;
  }
  static of(value) {
    return new Maybe(value);
  }
  map(fn) {
    return this.value == null ? this : Maybe.of(fn(this.value));
  }
  flatMap(fn) {
    return this.value == null ? this : fn(this.value);
  }
}

// 使用
Maybe.of(null)
  .map(x => x.toUpperCase()) // 不会执行
  .flatMap(x => Maybe.of(x + "!")); // 安全跳过

八、性能优化技巧

1.记忆化(Memoization)

缓存函数结果:

const memoize = (fn) => {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
};

// 使用
const factorial = memoize(n => n <= 1 ? 1 : n * factorial(n - 1));
console.log(factorial(5)); // 120 (仅计算一次)

2.惰性链式调用

避免不必要的中间数组(类似 Lodash 的链式调用):

const lazyChain = (data) => ({
  map: (fn) => lazyChain({
    *[Symbol.iterator]() {
      for (const item of data) yield fn(item);
    }
  }),
  filter: (fn) => lazyChain({
    *[Symbol.iterator]() {
      for (const item of data) if (fn(item)) yield item;
    }
  }),
  value: () => [...data]
});

// 使用
const result = lazyChain([1, 2, 3])
  .map(x => x * 2)
  .filter(x => x > 3)
  .value(); // [4, 6]

九、总结:高阶函数的深度价值

  1. 抽象复杂性:将多步骤逻辑封装为可复用的单元。
  2. 声明式编程:用 what to do 代替 how to do。
  3. 函数式模式:实现 Functor、Monad、IO 等高级模式。
  4. 性能优化:通过惰性计算和记忆化提升效率。
  5. 框架设计:支撑中间件、状态管理等架构模式。

实际应用建议

  • 在数据处理、异步流程、工具库开发中优先使用高阶函数
  • 结合 TypeScript 强化类型推导
  • 避免过度抽象,保持代码可读性
  • 使用 Lodash/fp、Ramda 等函数式库加速开发

通过深度应用高阶函数,可以将 JavaScript 代码提升到接近函数式语言(如 Haskell)的表达能力,同时保持 JavaScript 的灵活性。

最近发表
标签列表