纯函数是不依赖外部状态、不修改外部变量、相同输入恒返回相同输出的函数。它具备无副作用和引用透明两大特征,要求显式传入所有依赖、禁止修改参数、避免非确定性操作,从而提升测试简易性与代码可维护性。

纯函数是指不依赖外部状态、不修改外部变量、相同输入永远返回相同输出的函数。它像数学函数一样可预测,是函数式编程的核心概念,也是提升代码质量的关键实践。
纯函数的两个核心特征
要成为纯函数,必须同时满足以下两点:
- 无副作用(No Side Effects):不修改全局变量、不修改传入的对象或数组、不发起网络请求、不读写 DOM、不调用 console.log 或 alert 等影响外部环境的操作。
- 引用透明(Referential Transparency):对任意输入 x,f(x) 每次调用都返回完全相同的值,且结果只由 x 决定,不依赖时间、随机数、用户输入等不可控因素。
如何写出纯函数:关键操作原则
编写纯函数不是靠直觉,而是有明确的“禁令”和“推荐做法”:
- 禁止直接修改参数对象:若接收对象或数组,应使用展开运算符、Object.assign、Array.from 或结构赋值创建新副本,再处理。例如:return { ...obj, name: 'new' }; 而非 obj.name = 'new'; return obj;
- 避免使用 Date.now()、Math.random()、prompt() 等非确定性函数:如需随机数,可将随机值作为参数传入;如需时间戳,由调用方提供当前时间。
- 所有依赖显式声明为参数:不从闭包或模块顶层读取常量以外的变量。配置项、工具函数等都应通过参数传入,便于隔离与替换。
为什么纯函数让测试更简单
测试纯函数几乎不需要模拟(mock)或设置复杂上下文:
立即学习“Java免费学习笔记(深入)”;
- 输入即全部前提,输出即唯一断言目标。一行测试就能覆盖一个场景,例如:expect(add(2, 3)).toBe(5);
- 无需启动浏览器、不依赖网络、不担心数据库状态,单元测试运行飞快,可反复执行且结果稳定。
- 容易进行属性测试(Property-Based Testing),比如用 fast-check 验证“对任意 a、b,add(a,b) === add(b,a)”是否恒成立。
为什么纯函数提升长期可维护性
项目越大,副作用越容易引发“牵一发而动全身”的问题。纯函数天然规避这类风险:
- 函数行为完全自包含,阅读时无需跳转查看外部变量或副作用调用链。
- 可安全复用和组合:多个纯函数可通过 pipe、compose 自由拼接,形成清晰的数据流,例如:pipe(formatName, toUpperCase, addPrefix)。
- 重构放心:只要签名不变,内部实现可任意优化(如加缓存、换算法),调用方完全不受影响。











