什么是JavaScript纯函数_它为什么有益于测试?

14次阅读

纯函数是给定相同输入总返回相同输出且无副作用的函数,天然适合单元测试,因其无需模拟外部状态、重置变量或担心执行顺序。

什么是JavaScript纯函数_它为什么有益于测试?

纯函数在 javaScript 中不是语法特性,而是一种函数编写约定:给定相同输入,总是返回相同输出,且不产生任何可观察的副作用。它天然适合单元测试——因为无需模拟外部状态、不用重置全局变量、也不用担心执行顺序。

纯函数的两个硬性条件

一个函数要被称为“纯”,必须同时满足:

  • 无副作用:console.logdocument.querySelectorfetch、修改入参对象(如 arr.push)、修改闭包变量等都不允许
  • 输出仅依赖输入:math.random()date.now()、读取 window.innerWidth 等外部值会导致非纯

例如:

const add = (a, b) => a + b; // ✅ 纯   const now = () => Date.now(); // ❌ 非纯(每次调用结果不同)   const mutate = (arr) => { arr.push(1); return arr; }; // ❌ 非纯(修改了输入)

为什么纯函数让测试更简单?

测试时你只关心「输入 → 输出」映射,不需要:

  • 启动 mock 服务或拦截 fetch
  • 保存/恢复 localStorage 或 DOM 状态
  • 处理异步等待或定时器(纯函数必同步)
  • 担心多次 test() 调用相互污染

比如测试一个格式化金额的纯函数:

const formatMoney = (cents) => `$${(cents / 100).toFixed(2)}`;   // 测试只需断言:   expect(formatMoney(1250)).toBe('$12.50');   expect(formatMoney(0)).toBe('$0.00');

常见“伪纯”陷阱:看似纯,实则不纯

这些写法容易被误认为纯,但实际违反约束:

立即学习Java免费学习笔记(深入)”;

  • 使用 new Date()Math.random() —— 即使藏在深层调用里
  • 读取或修改闭包中的变量(如缓存 map、计数器)
  • 对对象参数做浅拷贝后修改属性({...obj} 后改 copy.name = 'x' 仍可能影响引用)
  • 调用另一个非纯函数(哪怕只有一行),整条链就不再是纯的

修复方式通常是把“外部依赖”显式传入,例如:

// ❌ 隐式依赖当前时间   const isExpired = (timestamp) => Date.now() > timestamp + 86400000;    // ✅ 改为接收 time 参数,测试时可自由控制   const isExpired = (timestamp, time = Date.now()) => time > timestamp + 86400000;

纯函数的价值不在“多酷”,而在降低测试的意外成本——一旦函数内部开始读写外部状态,你就要为每一次测试准备上下文、清理副作用、处理竞态,而这些开销会随代码增长指数上升。

text=ZqhQzanResources