面试官:说说你对函数式编程的理解

前言

面试中遇到一部分人对函数式编程不了解,还有一部分认为函数式编程除了面试中能用到,在自己的项目经验中很难看到具体的应用场景。

函数式编程作为一种编程范式由来已久。函数式编程强调不可变性和纯函数,即函数的输出仅由输入决定,没有副作用和对外部状态的依赖。这种特性使得函数式代码更易于理解、测试和调试。

函数式编程强调使用多个函数组合 和来处理数据。其核心是将运算过程抽象成函数,好处是可以复用

本文将尝试用通俗易懂的方式讲解函数式编程在前端项目中的应用。会对函数式编程进行简单的"扫盲",然后结合几个实例方便大家理解。

认识函数式编程

在开始之前,请先看一个函数式编程的实例。

js 复制代码
// 纯函数,只做一件事,输入输出,没有副作用
function double(number) {
  return number * 2;
}

function square(number) {
  return number * number;
}

// 不改变原来的数据,创建新的数组
function doubleArray(arr) {
  return arr.map(double);
}

function squareArray(arr) {
  return arr.map(square);
}

// 把多个函数组合成一个新的函数
function compose(...fns) {
  return function (x) {
    return fns.reduceRight(function(acc, fn){
      return fn(acc);
    }, x);
  };
}

const numbers = [1, 2, 3, 4, 5];
const processArray = compose(squareArray, doubleArray);
const result = processArray(numbers);

console.log(result); // [ 4, 16, 36, 64, 100 ]

有没有发现,函数式编程在实践中就像用乐高堆积木。

在这个例子中,先定义了两个纯函数。遵循不可变性原则对需要运算的数组进行新建而不是改变原有数据。最后把多个功能函数组合成一个新的函数,实现需要的功能。

纯函数

上面的实例中定义了两个纯函数 doublesquare。那么什么样的函数是纯函数呢?

根据定义,如果一个函数符合两个条件,它就可以被称为纯函数:

  1. 此函数在相同的输入值时,总是产生相同的输出。
  2. 次函数不会对除了函数返回值之外的任何东西产生可观察的副作用。不会修改传入的参数,也不会对全局状态进行更改,不会进行 I/O 操作,也不会触发网络请求等

由此可见,纯函数的执行仅仅是为了计算并返回一个值

下面是一个纯函数和非纯函数的对比实例。

js 复制代码
// 纯函数,不依赖于外部状态,相同的输入总是产生相同的输出
function add(a, b) {
  return a + b;
}

console.log(add(2, 3)); // 输出 5
console.log(add(2, 3)); // 输出 5

// 非纯函数,依赖于外部状态,相同的输入可能产生不同的输出
let result = 0;

function addToResult(value) {
  result += value;
  return result;
}

console.log(addToResult(5)); // 输出 5
console.log(addToResult(3)); // 输出 8

函数是一等公民

在函数式编程中,函数被视为一等公民。函数可以像其他数据类型(如整数、字符串等)一样被操作、传递和赋值。这种特性使得函数式编程具备更高的抽象能力和灵活性,可以更方便地实现函数的组合和重用。

1、函数可以被赋值给变量

js 复制代码
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;

const operation = add; // 函数赋值给变量

console.log(operation(2, 3)); // 输出: 5

operation = multiply; // 可以修改变量的值为另一个函数
console.log(operation(2, 3)); // 输出: 6

2、函数可以作为参数传递

js 复制代码
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;

const applyOperation = (a, b, operation) => operation(a, b);

console.log(applyOperation(2, 3, add)); // 输出: 5
console.log(applyOperation(2, 3, multiply)); // 输出: 6

3、函数可以作为返回值返回

js 复制代码
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;

const createOperation = (operator) => {
  if (operator === '+') {
    return add;
  } else if (operator === '*') {
    return multiply;
  }
};

const operation1 = createOperation('+');
console.log(operation1(2, 3)); // 输出: 5

const operation2 = createOperation('*');
console.log(operation2(2, 3)); // 输出: 6

函数组合

函数式编程中还有一个重要的思想就是组合(compose),它允许我们把逻辑通过函数的形式进行拆分,然后进行函数之间的组合最后得到想要的完整逻辑。文章开篇的实例中已经进行了演示,这里不做重复。

简言之函数式编程的实践就是对业务逻辑进行拆分,变成一个个纯函数,然后在组合成一个完整的逻辑模块。

这样做的好处很明显,简化逻辑,复用代码,方便写单元测试。

函数式编程库推荐

JavaScript 函数式编程的库有很多,以下是几个常用的库:

Ramda

Ramda 是一个专注于函数式编程的 JavaScript 库,提供了许多实用的函数和工具,用于支持函数式编程的开发风格。它强调不可变性、纯函数和柯里化,并提供了丰富的函数来处理和操作数据。

Lodash/fp

Lodash 是一个广泛使用的 JavaScript 实用工具库,而 Lodash/fp 则是 Lodash 的函数式编程版本。它提供了许多函数式风格的函数,并采用自动柯里化和数据优先的方式。

Immutable.js

Immutable.js 是一个用于处理不可变数据的 JavaScript 库。它提供了一组持久化的数据结构,如 List、Map、Set 等,以及一些用于操作这些数据结构的函数。通过使用 Immutable.js,可以更轻松地管理和操作不可变数据,避免副作用和数据修改。

RxJS

RxJS 是一个响应式编程库,它基于观察者模式和可观察序列(Observables)的概念。它提供了丰富的操作符和工具,用于处理异步数据流和事件序列。RxJS 支持函数式编程的思想,提供了一种声明式和组合的方式来处理异步操作。

总结

本文简单介绍了函数式编程的基本概念和特点,包括纯函数、函数是一等公民和函数组合。旨在能够让大家方便快速的理解函数数编程是什么。函数式编程可以提高代码的可读性、可维护性和并发性,非常值得学习和应用。

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试