《JavaScript 函数式编程指南》 - 阅读索引

2019-01-01  本文已影响9人  TWLESVCNZ

[toc]

第一部分 函数式思想

第 1 章 走近函数式

  • 函数式思想
  • 什么是函数式编程以及为什么要进行函数式编程
  • 不变性和纯函数的原则
  • 函数式编程技术及其对程序设计的影响

面向对象编程通过封装变化使得代码更易理解;函数式编程通过最小化变化使得代码更易理解。

1.1 函数式编程有用吗?

1.2 什么是函数式编程?

1.2.1 函数式编程是声明式编程

1.2.2 副作用带来的问题和纯函数

1.2.3 引用透明和可置换性

1.2.4 存储不可变的数据

函数式编程是指为创建不可变的程序,通过消除外部可见的副作用,来对纯函数的声明式的求值的过程

1.3 函数式编程的优点

1.3.1 鼓励复杂任务的分解

1.3.2 使用流式链来处理数据

1.3.3 复杂异步应用中的响应

1.4 总结

第 2 章 高阶 JavaScript

  • 为什么说 JS 是适合函数式的编程语言
  • JS 语言的多范型开发
  • 不可变性和变化的对策
  • 理解高阶函数和一等函数
  • 闭包和作用域的概念探讨
  • 闭包的实际使用

2.1 为什么要使用 JavaScript

2.2 函数式与面向对象的程序设计

函数式 面向对象
组合单元 函数 对象(类)
编程风格 声明式 命令式
数据和行为 独立且松耦合的纯函数 与方法紧耦合的类
状态管理 将对象视为不可变的值 主张通过实例方法改变对象
程序流控制 函数与递归 循环与条件
线程安全 可并发编程 难以实现
封装性 因为一切不可变,所以没有必要 需要保护数据的完整性

2.2.1 管理 JavaScript 对象的状态

2.2.2 将对象视为数值

function coordinate (lat, long) {
    let _lat = lat
    let _long = long
    return {
        translate (dx, dy) {
            return coordinate(_lat + dx, _long + dy)
        },
        toString () {   // 同纯函数,即该对象的字符串表示
            return `(${_lat}, ${_long})`
        }
    }
}

2.2.3 深冻结可变部分

2.2.4 使用 Lenses 定位并修改对象图

2.3 函数

2.3.1 一等函数

2.3.2 高阶函数

2.3.3 函数调用的类型

2.3.4 函数方法

2.4 闭包和作用域

2.4.1 全局作用域

2.4.2 函数作用域

2.4.3 伪块作用域

2.4.4 闭包的实际应用

2.5 总结


第二部分 函数式基础

第 3 章 轻数据结构,重操作

  • 理解程序的控制流
  • 更易理解的代码与数据
  • 命令抽象函数 map、reduce 以及 filter
  • Lodash.js 及函数链
  • 递归的思考

计算过程是计算机中的一种抽象存在,在其演化的过程中,这些过程会去控制另一种被称为数据的抽象存在。

3.1 理解程序的控制流

3.2 链接方法

3.3 函数链

3.3.1 了解 lambda 表达式

3.3.2 用 _.map 做数据变换

3.3.3 用 _.reduce 收集结果

3.3.4 用 _.filter 删除不需要的元素

3.4 代码推理

3.4.1 声明式惰性计算函数链

3.4.2 类 SQL 的数据:函数即数据

3.5 学会递归地思考

3.5.1 什么是递归?

3.5.2 学会递归地思考

3.5.3 递归定义的数据结构

3.6 总结

第 4 章 模块化且可重用的代码

  • 函数链与函数管道的比较
  • Ramda.js 函数库
  • 柯里化、部分应用和函数绑定
  • 通过函数式组合构建模块化程序
  • 利用函数组合子增强程序的控制流

4.1 方法链与函数管道的比较

4.1.1 方法链接

4.1.2 函数的管道化

4.2 管道函数的兼容条件

4.2.1 函数的类型兼容条件

4.2.2 函数与元数:元组的应用

4.3 柯里化的函数求值

4.3.1 仿真函数工厂

4.3.2 创建可重用的函数模板

4.4 部分应用和函数绑定

4.4.1 核心语言扩展

4.4.2 延迟函数绑定

4.5 组合函数管道

4.5.1 HTML 部件的组合

4.5.2 函数组合:描述与求值分离

4.5.3 函数式库的组合

4.5.4 应对纯的代码和不纯的代码

4.5.5 point-free 编程

4.6 使用函数组合子来管理程序的控制流

4.6.1 identity(I 组合子)

4.6.2 tap(K 组合子)

使用如下

const sayX = x => console.log('x is ' + x);
R.tap(sayX, 100); //=> 100

4.6.3 alt(OR 组合子)

4.6.4 seq (S 组合子)

实现如下

const seq = function (...fnss) {
    return function (value) {
        fns.forEach(function (fn) {
            fn(value)
        })
    }
}

4.6.4 fork(join)组合子

实现如下

const fork = function (join, f, g) {
    return function (value) {
        return join(f(value), g(value))
    }
}

4.7 总结

第 5 章 针对复杂应用的设计模式

  • 命令式处理异常方式的问题
  • 使用容器,以防访问无效数据
  • 用 Functor 的实现来做数据转换
  • 利于组合的 Monad 数据类型
  • 使用 Monadic 类型来巩固错误处理策略
  • Monadic 类型的组合与交错

5.1 命令式错误处理的不足

5.1.1 用 try-catch 处理错误

5.1.2 函数式程序不应抛出异常

5.1.3 空值(null)的检查问题

5.2 一种更好的解决方案——Functor

5.2.1 包裹不安全的值

5.2.2 Functor 定义

5.3 使用 Monad 函数式地处理错误

5.3.1 Monad:从控制流到数据流

5.3.2 使用 Maybe Monad 和 Either Monad 来处理异常

5.3.3 使用 IO Monad 与外部资源交互

5.4 Monadic 链式调用及组合

5.5 总结


第三部分 函数式技能提升

第 6 章 坚不可摧的代码

  • 函数式编程会如何改变测试方法
  • 认识到测试命令式代码的挑战
  • 使用 QUnit 测试函数式代码
  • JSCheck 探索属性测试
  • 使用 Blanket 测试程序的复杂性

6.1 函数式编程对单元测试的影响

6.2 测试命令代码的困难

6.2.1 难以识别和分解任务

6.2.2 对共享资源的依赖会导致结果不一致

6.2.3 按预定义顺序执行

6.3 测试函数式代码

6.3.1 把函数当做黑盒子

6.3.2 专注于业务逻辑,而不是控制流

6.3.3 使用 Monadic 式从不纯的代码中分离出纯函数

6.3.4 mock 外部依赖

6.4 通过属性测试制定规格说明

6.5 通过代码覆盖率衡量有效性

6.5.1 衡量函数式代码测试的有效性

6.5.2 衡量函数式代码的复杂性

6.6 总结

第 7 章 函数式优化

  • 如何识别高性能的函数式代码
  • JavaScript 函数执行的内部机制
  • 嵌套函数的背景和递归
  • 使用惰性求值优化函数调用
  • 使用记忆化加速程序执行
  • 使用尾递归函数展开递归调用

7.1 函数执行机制

7.1.1 柯里化与函数上下文堆栈

7.1.2 递归的弱点

7.2 使用惰性求值推迟执行

7.2.1 使用函数式组合子避免重复计算

7.2.2 使用 shortcut fusion

7.3 实现需要时调用的策略

7.3.1 理解记忆化

7.3.2 记忆化计算密集型函数

7.3.3 有效利用柯里化与记忆化

7.3.4 通过分解来实现更大程度的记忆化

7.3.5 记忆化递归调用

7.4 递归和尾递归优化

const factorial = n => (n === 1) ? 1 : n * (factorial(n - 1))
    // ->
const factorial = (n, current = 1) => (n === 1) ? current : factorial(n - 1, n * current)

7.5 总结

第 8 章 管理异步事件以及数据

  • 编写异步代码的挑战
  • 通过函数式技术避免嵌套回调
  • 使用 Promise 简化异步代码
  • 用函数生成器惰性地生成数据
  • 响应式编程
  • 应用响应式编程来处理事件驱动的代码

8.1 异步代码的挑战

8.1.1 在函数之间创建时间依赖关系

8.1.2 陷入回调金字塔

8.1.3 使用持续传递式样

8.2 一等公民 Promise

8.2.1 链接将来的方法

8.2.2 组合同步和异步行为

8.3 生成惰性数据

8.3.1 生成器与递归

8.3.2 迭代器协议

8.4 使用 RxJS 进行函数式和响应式编程

8.4.1 数据作为 Observable 序列

8.4.2 函数式编程与响应式编程

8.4.3 RxJS 和 Promise

8.5 总结

上一篇 下一篇

猜你喜欢

热点阅读