百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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

itomcoil 2025-04-05 19:24 6 浏览

一、什么是高阶函数?

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

  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 的灵活性。

相关推荐

PS小技巧 调整命令,让人物肤色变得更加白皙 #后期修图

我们来看一下如何去将人物的皮肤变得更加的白皙。·首先选中图层,Ctrl键加J键复制一层。·打开这里的属性面板,选择快速操作删除背景,这样就会将人物进行单独的抠取。·接下来在上方去添加一个黑白调整图层,...

把人物肤色提亮的方法和技巧

PS后期调白肤色提亮照片的方法。一白遮百丑,所以对于Photoshop后期来说把人物肤色调白是一项非常重要的任务。就拿这张素材图片来说,这张素材图片人脸的肤色主要偏红、偏黄,也不够白皙,该怎样对它进行...

《Photoshop教程》把美女图片调成清爽色彩及润肤技巧

关注PS精品教程,每天不断更新~~室内人物图片一般会偏暗,人物脸部、肤色及背景会出现一些杂点。处理之前需要认真的给人物磨皮及美白,然后再整体润色。最终效果原图一、用修补工具及图章工具简单去除大一点的黑...

PS后期对皮肤进行美白的技巧

PS后期进行皮肤美白的技巧。PS后期对皮肤进行美白的技巧:·打开素材图片之后直接复制原图。·接下来直接点击上方的图像,选择应用图像命令。·在通道这里直接选择红通道,混合这里直接选择柔光,然后点击确定。...

493 [PS调色]调模特通透肤色

效果对比:效果图吧:1、光位图:2、拍摄参数:·快门:160;光圈:8;ISO:1003、步骤分解图:用曲线调整图层调出基本色调。用可选颜色调整图层调整红色、黄色、白色和灰色4种颜色的混合比例。用色彩...

先选肤色再涂面部,卡戴珊的摄影师透露:为明星拍完照后怎么修图

据英国媒体12月17日报道,真人秀明星金·卡戴珊终于承认,她把女儿小北P进了家族的圣诞贺卡,怪不得粉丝们都表示这张贺卡照得非常失败。上周,这位39岁的女星遭到了一些粉丝针对这张照片的批评,她于当地时间...

如何在PS中运用曲线复制另一张照片的色调

怎样把另一张作品的外观感觉,套用到自己的照片上?单靠肉眼来猜,可能很不容易,而来自BenSecret的教学,关键是在PS使用了两个工具,让你可以准确比较两张照片的曝光、色调与饱和度,方便你调整及复制...

PS在LAB模式下调出水嫩肤色的美女

本PS教程主要使用Photoshop使用LAB模式调出水嫩肤色的美女,教程调色比较独特。作者比较注重图片高光部分的颜色,增加质感及肤色调红润等都是在高光区域完成。尤其在Lab模式下,用高光选区调色后图...

在Photoshop图像后期处理中如何将人物皮肤处理得白皙通透

我们在人像后期处理中,需要将人物皮肤处理的白皙通透,处理方法很多,大多数都喜欢使用曲线、磨皮等进行调整,可以达到亮但是不透,最终效果往往不是很好,今天就教大家一种如何将任务皮肤处理得白皙通透,希望能帮...

PS调色自学教程:宝宝照片快速调通透,简单实用!

PS调色自学教程:宝宝照片快速调通透。·首先复制图层,然后选择进入ACR滤镜,选择曲线锁定照片的亮部,也就高光位置,其他部位补亮一点,尤其是阴影的部位补亮多一些,让画面的层次均匀一点。·然后回到基本项...

【干货】如何利用PS进行人物美化

人物图像美化在Photoshop中非常常用,Photoshop作为一款功能强大的图像处理软件,不仅可以对人像进行基本的调色、美化和修复等处理,还可以改变人物的线条和幅度,如调整脸部器官和脸型的大小、调...

教大家一种可以快速把肤色处理均匀的方法@抖音短视频

快速把肤色处理均匀的方法。今天教大家一种可以快速把肤色处理均匀的方法。像这张照片整体肤色走紫红色,但是局部偏黄缘处理起来非常的麻烦。其实我们只需要新建空白图层,图层混合模式更改为颜色,再选择画笔工具把...

PS调色教程 利用RAW调出干净通透的肤色

要么不发,要么干货。后期教程来噜~用RAW调出干净通透的肤色。这次终于不会原片比PS后好看了吧。如果你依然这么觉得,请不要残忍的告诉我这个事实,泪谢TAT)附送拍摄花絮,感谢各位的支持更多风格请关注m...

photoshop后期皮肤变白的技巧

PS后期皮肤变白的技巧。1.PS后期让皮肤变白的方法有很多种,接下来教你一种非常简单容易上手的方法。2.打开素材图片之后,直接在小太极下拉框的位置添加一个纯色调整图层,颜色设置一个纯白色,点击...

Photoshop调出人物的淡雅粉嫩肤色教程

本教程主要使用Photoshop调出人物的淡雅粉嫩肤色教程,最终的效果非常的通透迷人,下面让我们一起来学习.出自:86ps效果图:原图:1、打开原图复制一层。2、用Topaz滤镜磨皮(点此下载)。3、...