纯函数是输入确定则输出必确定、且无任何副作用的函数;它要求确定性(同输入恒得同输出)和无副作用(不修改外部状态),使测试更简单可靠、结果可复现、易于组合与缓存。

JavaScript 纯函数就是输入确定、输出就一定确定,且不碰外部世界任何东西的函数。它对测试重要,不是因为“听起来高级”,而是让测试从“猜环境、mock一堆东西”变成“给两个数,看是不是等于五”这么直接。
纯函数的两个硬性条件
一个函数要算纯,必须同时满足:
-
确定性:相同参数,每次调用都返回完全一样的值。比如
add(2, 3)永远是5,不能依赖Date.now()、Math.random()、localStorage或某个全局变量。 -
无副作用:不修改传入的对象或数组(如不用
arr.push()或obj.name = 'x'),不发请求、不操作 DOM、不调用console.log、不改全局状态。
怎么写出真正纯的函数
关键不在“想纯”,而在具体操作上守住几条线:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 所有依赖都显式传参——时间戳、API 地址、随机种子,全得由调用方给,不能自己偷偷去读。
- 对象/数组参数一律不直接改,用展开运算符、
map/filter/reduce、structuredClone或Object.assign({}, obj)创建新数据。 - 避免隐式闭包污染:不要在函数内部引用模块顶层定义的可变变量,比如把
const API_BASE = 'https://...'写成参数(url, id) => fetch(`${url}/users/${id}`)。 - 慎用默认参数做逻辑判断,比如
(x = x || {})会把0、false、null都转成空对象,破坏输入真实性。
为什么测试特别受益
纯函数把“不可控因素”全部挡在门外,测试时自然省心省力:
立即学习“Java免费学习笔记(深入)”;
- 断言极简:只关心输入和输出,不用 mock 时间、网络、DOM,也不用重置全局状态。
- 结果可复现:同一组测试用例跑一百遍,结果不变;CI 失败就一定是逻辑问题,不是环境抖动。
-
容易组合验证:比如
compose(validate, sanitize, save),每个环节单独测过,组合起来也大概率稳。 - 支持记忆化与快照比对:输出只取决于输入,就可以缓存结果,也能放心用快照测试(snapshot)固化预期结构。
副作用不是bug,只是得放对地方
真实代码离不开发请求、读时间、写 localStorage——但这些不该混在计算逻辑里。推荐做法是:
- 把副作用封装成独立函数,比如
fetchUser(id)、logError(msg),命名就带提示(如带Effect或IO后缀)。 - 业务主流程用纯函数处理数据转换,副作用只出现在边界层(如 React 组件的
useEffect、自定义 Hook 或服务层入口)。 - 异步操作统一用 Promise 表达,避免在纯函数里写
fetch().then(...)这类立即触发的行为。

















