Skip to content

1. 核心概念 (Core Concept)

  • 纯函数 (Pure Function):指满足两个条件的函数:给定相同的输入,总是返回相同的输出;并且执行过程中没有任何可观察的副作用。
  • 副作用 (Side Effect):指函数执行时,除了返回显而易见的计算结果外,还对外部世界产生了可观察的影响,例如修改全局变量、I/O 操作(读写文件、网络请求)、修改 DOM 等。
  • 函数式编程 (Functional Programming):一种编程范式,强调使用纯函数、避免改变状态和可变数据,并使用函数作为一等公民。它将计算视为数学函数的求值。

2. 为什么需要它? (The "Why")

  • 可预测性与可测试性 (Predictability & Testability): 纯函数由于其确定的输入和输出,极大地提高了代码的可预测性,使得单元测试变得非常简单,只需测试输入与输出的关系即可。
  • 并发与并行安全性 (Concurrency & Parallel Safety): 纯函数不依赖或修改外部状态,天然适用于并发和并行环境,避免了多线程或多进程共享状态带来的复杂同步问题(如竞态条件)。
  • 代码理解与推理 (Code Understanding & Reasoning): 副作用使得代码的行为难以追踪,因为它的行为取决于外部状态。纯函数将复杂性局部化到函数内部,使得代码更容易理解和推导其行为。

3. API 与用法 (API & Usage)

纯函数本身不是一个具体的 API,而是函数的一种属性或一种编写函数的方式。函数式编程也没有特定的内置 API(在通用编程语言如 JavaScript 中),它更多是一种编程风格和思想。

纯函数的例子(JavaScript):

javascript
// 纯函数:给定相同的输入 (a, b),总是返回相同的输出 (a + b),没有副作用。
function add(a, b) {
  return a + b;
}

// 非纯函数的例子 (含有副作用):
// 例子 1: 依赖外部状态
let count = 0;
function incrementAndGet() {
  count++; // 修改外部变量,副作用
  return count;
}

// 例子 2: 修改传入的参数 (如果参数是引用类型)
function modifyArray(arr) {
  arr.push(1); // 修改了函数外部的数组,副作用
  return arr;
}

// 例子 3: 进行 I/O 操作
function logMessage(message) {
  console.log(message); // 写入到控制台,副作用 (尽管这是常见的操作)
}

// 例子 4: 读取外部状态
function getRandomNumber() {
  return Math.random(); // 依赖 Math 的内部状态(或者说依赖时间等外部因素),每次结果不同,非纯函数
}

在函数式编程中,我们通常会结合使用高阶函数(Higher-Order Functions,如 map, filter, reduce)和纯函数来处理数据:

javascript
// 使用纯函数和高阶函数处理数组
const numbers = [1, 2, 3, 4, 5];

// 使用 map (高阶函数),传入一个纯函数 (num => num * 2)
// map 本身是纯的,它返回一个新数组,不修改原数组
const doubledNumbers = numbers.map(num => num * 2); // [2, 4, 6, 8, 10]

// 使用 filter (高阶函数),传入一个纯函数 (num => num > 2)
// filter 本身是纯的,它返回一个新数组
const greaterThanTwo = numbers.filter(num => num > 2); // [3, 4, 5]

// 使用 reduce (高阶函数),传入一个纯函数 ((acc, num) => acc + num)
// reduce 本身是纯的,它返回一个单一值
const sum = numbers.reduce((acc, num) => acc + num, 0); // 15

console.log("Original:", numbers); // [1, 2, 3, 4, 5] - 原数组未被修改
console.log("Doubled:", doubledNumbers);
console.log("Filtered:", greaterThanTwo);
console.log("Sum:", sum);

4. 关键注意事项 (Key Considerations)

  • 并非所有函数都能是纯函数: 在实际应用中,完全没有副作用的程序是不可能的(比如最终需要将结果显示给用户,这就需要 I/O 副作用)。关键在于控制副作用,将其隔离在程序的边缘
  • 修改引用类型参数的陷阱: JavaScript 中,Objects 和 Arrays 是通过引用传递的。如果函数修改了作为参数传入的引用类型对象或数组,就产生了副作用。为了保持纯净,应返回新的对象或数组,而不是修改原有的。可以使用展开运算符 ...slice()map()filter() 等方法创建副本。
  • 理解状态管理的边界: 在前端框架(如 React、Vue)中处理状态时,理解何时需要管理具有副作用的状态(如组件状态、全局状态)以及何时使用纯函数进行计算,是构建可维护应用的关键。许多现代状态管理库(如 Redux, Vuex, Zustand)都鼓励使用纯函数(如 Reducers)来更新状态。
  • 性能与纯度折衷: 虽然纯函数有诸多优点,但在极少数对性能有苛刻要求的场景下,为了避免创建大量新对象/数组,可能会选择有限度的修改,但这通常需要小心权衡和处理。

5. 参考资料 (References)


不知道说啥了很无语了