如何用javascript编写纯净的函数式代码【教程】

10次阅读

javaScript虽非纯函数式语言,但可通过规避副作用、坚持不可变性、避免共享状态来写出接近纯净的函数式代码;纯净函数要求相同输入恒得相同输出且无任何可观察副作用。

如何用javascript编写纯净的函数式代码【教程】

javascript 本身不是纯函数式语言,但你可以写出接近纯净的函数式代码——关键不在“能不能”,而在“是否主动规避副作用、是否坚持不可变性、是否避免共享状态”。

什么是纯净函数?先看一个反例

纯净函数必须满足两个条件:相同输入永远返回相同输出;不产生任何可观察的副作用(比如修改全局变量、发请求、操作 dom、修改入参)。

常见污染点:Array.prototype.pushArray.prototype.sortObject.assign(当第一个参数是原对象时)、直接赋值 obj.key = value

错误写法示例:

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

const addTodo = (list, text) => {   list.push({ id: Date.now(), text }); // ❌ 修改了原数组   return list; };

正确写法应返回新数组:

const addTodo = (list, text) => [   ...list,   { id: Date.now(), text } ];

const 和不可变数据结构约束自己

const 只保证绑定不被重新赋值,不阻止对象/数组内部被修改。所以得靠习惯和工具辅助。

  • 默认用扩展运算符 [...arr]{...obj} 创建新副本
  • mapFilterreduce 替代 for 循环(它们天然不修改原数组)
  • 对深层嵌套对象,避免手写深拷贝;小项目可用 jsON.parse(json.Stringify(obj))(仅限简单数据),大项目考虑 immerlodash/fpset/update
  • 函数参数不加 default 值以外的赋值逻辑,比如避免 (x = x || {}) —— 这会掩盖传入 NULL0 的意图

如何处理真实世界里的副作用?

http 请求、时间、随机数、DOM 操作这些无法消除,但可以隔离。

把副作用“推到边缘”:

  • 把 API 调用封装进单独函数,如 fetchUser(id),它只负责发起请求,不处理渲染或状态更新
  • 用高阶函数接收回调,而非在函数内部调用 console.logdocument.querySelector
  • 异步流程优先用 async/await + promise 链,避免在 then 中直接修改外部变量
  • 如果用 Redux,确保所有 reducer 是纯净的;副作用交给 redux-thunkredux-saga 处理

例如,这个函数就混杂了逻辑与副作用:

const loadProfile = async (id) => {   const res = await fetch(`/api/users/${id}`);   const data = await res.json();   document.getElementById('name').innerText = data.name; // ❌ 侵入 DOM   return data; };

应该拆成:

const fetchProfile = async (id) => {   const res = await fetch(`/api/users/${id}`);   return res.json(); // ✅ 只做数据获取 };  // 使用方决定怎么渲染 fetchProfile(123).then(data => {   document.getElementById('name').innerText = data.name; });

工具链能帮你守住底线吗?

不能完全替代意识,但能显著降低出错概率。

  • ESLint 插件 eslint-plugin-functional 可检测 mutating propsno-letno-loop-statement
  • typescript 配合 readonly 修饰符(如 readonly items: string[])能在编译期提示非法修改
  • 运行时防护:小项目可用 deep-freeze开发环境冻结 props/state,一旦被改就抛错
  • 注意:Babel 编译后的代码可能绕过某些检查,别盲目信任构建产物

最常被忽略的一点:函数式风格不等于composepipe。过度抽象会让错误堆难读、调试变慢。该直白时就直白,尤其在边界处(I/O、事件处理、初始化逻辑)。

text=ZqhQzanResources