Skip to content

前言

深入浅出函数式编程:从技巧到思维的跃迁

第一章:重新理解函数式编程的本质

  • 函数式编程不是“用 map 替代 for 循环”
    它是一种以函数为基本构造单元的编程范式,核心是表达“做什么”而非“怎么做”
  • 纯函数:为什么它能消除副作用?
    相同输入 → 相同输出 + 无外部影响,是可测试、可缓存、可并行的基础
  • 副作用(Side Effect)的七宗罪
    修改全局变量、DOM 操作、网络请求、时间依赖、随机数、异常抛出、日志打印
  • 引用透明性:表达式可替换为值的前提
    为什么 f(x) === f(x) 成立时,代码才真正“可推理”?
  • 声明式 vs 指令式:两种思维模式的对比
    users.filter(u => u.age > 18) vs 手写 for 循环 + push

第二章:掌握函数式核心机制

  • 高阶函数:函数为何能作为参数和返回值?
    基于闭包与 [[Environment]] 的能力,实现函数的组合与抽象
  • 柯里化(Currying):为什么 add(1)(2)(3) 是合法的?
    将多参数函数转换为单参数函数链,实现参数的“预填充”
  • 函数组合(Composition):f(g(x)) 的优雅写法 compose(f, g)(x)
    数学中的 f ∘ g 在 JS 中的实现与结合律优势
  • 偏应用(Partial Application) vs 柯里化
    固定部分参数生成新函数,但不强制一次只传一个
  • 惰性求值(Lazy Evaluation):为什么 Ramda 的操作可以“延迟执行”?
    利用闭包与 thunk 实现“按需计算”,避免不必要的中间结果

第三章:穿透不可变性与数据结构

  • 不可变性(Immutability):为什么不能 push,而要用 concat
    避免状态突变带来的“意料之外”的修改,保证数据流可追踪
  • 结构共享(Structural Sharing):Immutable.js 如何高效更新树?
    利用持久化数据结构(Persistent Data Structures)复用未变节点
  • 递归:函数式中的“循环替代品”
    为什么尾递归在 JS 中受限?如何用 trampoline 避免栈溢出?
  • 函子(Functor):map 背后的统一抽象
    任何能 map 的类型(Array、Maybe、Observable)都是函子
  • Either 与 Maybe:用类型表达“可能失败”的计算
    替代 if (data) { ... } else { ... },让错误处理变得“可组合”

第四章:深入范畴论与类型系统

  • 范畴(Category)的三个要素:对象、态射、恒等
    编程中的“类型”是对象,“函数”是态射,“id”是恒等函数
  • Monad:为什么 Promise 是 Monad?
    flatMapthen)满足左单位律、右单位律、结合律
  • Applicative:介于 Functor 与 Monad 之间的抽象
    支持多个上下文值的函数应用(如 liftA2(add, Maybe(1), Maybe(2))
  • 代数数据类型(ADT):如何用 JS 模拟 Sum 与 Product 类型?
    Either(Sum)、Tuple(Product)的实现与模式匹配
  • 类型类(Typeclass):JS 中的“接口”模拟
    Semigroup(可合并)、Monoid(带单位元的 Semigroup)

第五章:在 JS 中安全实践函数式

  • 函数式与闭包的共生关系
    柯里化、组合、惰性求值都依赖闭包,但需警惕内存泄漏
  • 函数式与性能:深拷贝、递归、中间数组的代价
    何时该“妥协”?生产环境中的权衡策略
  • 函数式与 React:为什么 Hooks 天然适合 FP?
    useState 是 State Monad?useReducer 是纯函数驱动?
  • 函数式与 RxJS:Observable 是 Monad 吗?
    mapflatMapfilter 的函子/单子特性
  • 渐进式函数式:如何在现有项目中引入 FP 思维?
    从纯函数工具函数开始,逐步替换命令式逻辑

第六章:高级技巧与工程实践

  • 自动柯里化:如何让普通函数支持 f(1,2,3)f(1)(2)(3)
    利用闭包与参数长度检测实现灵活调用
  • 函数管道(pipe) vs 组合(compose)
    pipe(f, g, h)(x) 更符合阅读顺序,compose(h, g, f)(x) 符合数学习惯
  • 错误传播:如何让 MaybeEither 链式处理失败?
    避免层层 if (result) return ...
  • 状态传递:如何在无 this 的情况下管理状态?
    使用 State Monad 模拟“可变状态”的纯函数表达
  • 测试优势:纯函数为何天生适合单元测试?
    无需 mock,输入输出明确,覆盖率高