
纯函数是函数式编程的基石,其核心标准仅有两条:输入相同时输出恒定不变,且执行过程不产生任何副作用(如修改全局变量、i/o操作等);返回值本身绝非副作用,字符串字面量等常量亦不破坏纯性。
纯函数是函数式编程的基石,其核心标准仅有两条:输入相同时输出恒定不变,且执行过程不产生任何副作用(如修改全局变量、i/o操作等);返回值本身绝非副作用,字符串字面量等常量亦不破坏纯性。
在函数式编程实践中,能否准确识别纯函数,直接关系到代码的可测试性、可组合性与并发安全性。但初学者常因概念混淆而误判——例如,将“返回字符串”或“使用字符串常量”错误理解为“有副作用”,这本质上是对纯函数定义的误解。
✅ 正确理解纯函数的两大铁律:
- 确定性(Determinism):对任意相同输入,函数必须始终返回完全相同的输出。
-
无副作用(No Side Effects):函数执行过程中不得:
• 修改任何外部可变状态(如全局变量、对象属性、数组元素);
• 触发 I/O 操作(如console.log、fetch、localStorage.setItem);
• 改变传入的可变参数(如arr.push());
• 依赖随时间/上下文变化的外部值(如Date.now()、Math.random()、未声明的自由变量)。
⚠️ 常见误区澄清:
- ❌ “返回值”不是副作用 —— 函数的本职就是计算并返回结果。
return "Hi, I'm " + name完全合法,"Hi, I'm "是编译期确定的不可变字面量,不构成外部依赖。 - ❌ “字符串拼接”不引入外部状态 —— 只要所有参与运算的值均来自参数或内部常量,即满足封闭性。
- ✅ 对比验证:以下函数均为纯函数:
// 纯:仅依赖参数,返回新字符串
const greet = (name) => `Hi, I'm ${name}`;
// 纯:常量 42 是确定性的一部分
const add42 = (x) => x + 42;
// 纯:闭包中捕获的常量不影响纯性
const makeGreeting = (prefix) => (name) => `${prefix}, ${name}`;
const helloGreet = makeGreeting("Hello");
console.log(helloGreet("Alice")); // "Hello, Alice" —— 每次调用结果一致
❌ 而这些则是典型的不纯函数:
let counter = 0;
const impureInc = () => ++counter; // 修改外部变量 → 副作用
const logAndReturn = (x) => {
console.log(x); // I/O 副作用
return x * 2;
};
const unreliableNow = () => Date.now(); // 依赖时间 → 非确定性
const mutateArray = (arr) => {
arr.push(1); // 修改入参 → 副作用(即使参数是引用类型)
return arr;
};
? 进阶提示:纯性 ≠ 语法形式,而取决于行为语义。
即使函数体包含看似“危险”的操作(如闭包、高阶函数),只要其整体行为满足确定性与无副作用,它仍是纯的。例如,React 中的 useMemo(() => computeExpensiveValue(a, b), [a, b]) 的回调若本身是纯函数,则整个 memoized 计算仍保持纯性边界。
总结而言,判断纯函数,请始终回归本质提问:
? 给定同一组参数,它是否永远返回同一结果?
? 执行它,是否会悄悄改变世界(内存、界面、文件、网络等)?
若两个答案均为“是”,那它就是值得信赖的纯函数——简洁、可预测、易于推理,是构建健壮函数式系统的第一块基石。










