Functor 和 Monad 是 JavaScript 中处理数据包裹、副作用和流程控制的实用模式,核心价值在于用统一接口应对不确定性、异步性和错误分支,提升逻辑可预测性与可组合性。

Functor 和 Monad 不是抽象数学游戏,而是 JavaScript 中处理数据包裹、副作用和流程控制的实用模式。它们的核心价值在于:用统一接口应对不确定性(null/undefined)、异步性、错误分支,让逻辑更可预测、可组合。
Functor:让“带上下文的值”也能被函数安全操作
Functor 本质是一个实现了 map 方法的容器。它不让你直接取值,而是提供一个通道,把函数“送进去”作用于内部值,并返回同类型的新容器。
- 数组是最常见的 Functor:
[1, 2, 3].map(x => x * 2)返回新数组,原数组不变,且映射规则满足恒等性(.map(x => x)不变)和组合性(.map(f).map(g) === .map(x => g(f(x)))) - 自定义 Maybe Functor 可避免
null崩溃:Maybe.of(null).map(x => x.toUpperCase())直接返回Maybe.of(null),不会报错;Maybe.of("hello").map(x => x.toUpperCase())返回Maybe.of("HELLO") - 函数本身也是 Functor:
const f = x => x + 1;R.map(x => x * 2, f)(Ramda)等价于x => (x + 1) * 2,即对函数“整体”做变换
Monad:解决“函数返回容器”导致的嵌套问题
当 map 的函数返回的不是普通值,而是另一个 Functor(比如 Maybe 或 Promise),就会产生嵌套:Maybe.of(5).map(x => Maybe.of(x * 2)) 得到 Maybe.of(Maybe.of(10)) —— 这就是 Monad 要扁平化的场景。
- Monad 在 Functor 基础上增加 chain(或
flatMap)方法:Maybe.of(5).chain(x => Maybe.of(x * 2))直接返回Maybe.of(10),自动展开一层 -
Promise 就是典型的 Monad:
fetch("/api").then(res => res.json())中,回调既可返回普通值(如"ok"),也可返回新 Promise(如fetch("/data")),then内部自动resolve或透传,避免了.then(...).then(...).then(...)的深层嵌套 - Either Monad 用于错误处理:
成功路径走Right,失败走Left;parseJSON(str).chain(json => validate(json)).map(data => save(data)),任意一步出错就短路进Left分支,无需 try/catch 拦截
为什么在 JS 里值得用?不是造轮子吗?
不是为了炫技,而是为了解决真实痛点:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 替代散落各处的
if (x != null)和try...catch,把空值/错误处理逻辑收束到类型契约中 - 让异步链更线性:Promise.then 链本质就是 Monad chain,写法自然,错误可集中捕获
- 配合 Ramda、Folktale、Crocks 等库,能写出声明式、无副作用的业务逻辑,比如表单校验、状态转换、API 编排
- 类型系统友好:TypeScript 中可配合泛型精准描述容器行为,提升可维护性
入门建议:从 Promise 和 Array 开始理解
不必一上来就手写 Maybe 或 Either。先真正读懂这两行代码背后的契约:
-
[1, 2, 3].map(x => x.toString()).map(x => x.length)→ Functor 的组合性 -
Promise.resolve(1).then(x => Promise.resolve(x + 1)).then(x => x * 2)→ Monad 的扁平化能力 - 再对比:
Promise.resolve(1).then(x => x + 1).then(x => x * 2)→ 同样成立,因为 Promise.then 已内置 chain 语义
理解了这两点,你就已经站在函数式思维的门口了。


















