发表于2024-11-22
1、涵盖大部分函数式编程思想
2、幽默风趣,通俗易懂
3、是Clojure风格的JavaScript
4、用JavaScript实现了很多奇技淫巧
5、所有开发者都可以在本书中找到一些启发
在后端,函数式语言层出不穷。在前端,函数式最后的边界也已经被渐渐打破。Scala的Scala.js、Clojure的ClojureScript都试图同构移向前端。然而,原生JavaScript其实也可以通过丰富的库让前端的函数式编程一样的舒适和优雅。本书涵盖了大部分函数式编程思想,包括JavaScript的函数式支持,Clojure风格的集合、递归、函数组合、宏、模式匹配、实用的Monads,以及前端的并发编程。本书适合想要了解函数式编程的JavaScript程序员或者想学习JavaScript的函数式程序员阅读。
欧阳继超,ThoughtWorks高级咨询师,活跃开源贡献者(github.com/jcouyang),热爱编程与写作,译有《函数式JavaScript》以及若干开源书籍与文档。
作为 Ramda.js 的作者之一,我非常喜欢 Braithwaite 的《JavaScript Allonge》,喜欢 Fogus 的《Functional JavaScript》,我非常激动又有一本关于JavaScript的函数式书籍,希望尽快能见到这本书的英文版。
—— CrossEye
第1章 函数式JavaScript 1
1.1 JavaScript也是函数式语言吗 1
1.1.1 编程范式 1
1.1.2 JavaScript的函数式支持 3
1.2 作为函数式语言,JavaScript还差些什么 10
1.2.1 不可变数据结构 11
1.2.2 惰性求值 11
1.2.3 函数组合 12
1.2.4 尾递归优化 13
1.3 Underscore你错了 14
1.3.1 跟大家都不一样的 map 函数 14
1.3.2 ClojureScript 16
1.3.3 Mori 17
1.4 小结 18
第2章 集合 19
2.1 集合的使用 20
2.1.1 向量(vector) 20
2.1.2 Map 23
2.1.3 函数组合子 24
2.2 持久性数据结构 27
2.2.1 向量的持久性数据结构 28
2.2.2 最后一片叶子不完整 31
2.2.3 所有叶子完整且叶子个数不大于完全树的叶子个数 32
2.2.4 所有叶子完整且叶子个数大于完全树的叶子个数 34
2.3 不可变性 35
2.3.1 致命魔术 36
2.3.2 引用透明性 38
2.3.3 函数式React 40
2.3.4 线程不安全 42
2.4 惰性序列 44
2.4.1 改良奥利奥吃法 44
2.4.2 惰性求值与及早求值 46
2.4.3 惰性求值的实现 48
2.5 小结 50
第3章 递归 51
3.1 不可变性与递归 51
3.1.1 真的需要循环吗 52
3.1.2 递归还是循环 54
3.2 柯里悖论 55
3.2.1 Y组合子 57
3.2.2 栈是多么容易爆 60
3.3 尾递归优化 62
3.4 蹦跳乐园(Trampoline) 64
3.4.1 有穷状态机(DFA) 65
3.4.2 Trampoline 67
3.5 小结 69
第4章 函数组合 70
4.1 Underscore到底做错了什么 70
4.1.1 自由(Free)变量与约束(Bound)变量 72
4.1.2 闭包 74
4.2 柯里化有什么用 75
4.3 Transducer 78
4.3.1 Reducer 79
4.3.2 来看看更好更快的解法 79
4.3.3 Reducer 80
4.3.4 Reducible 81
4.3.5 Transducer详解 82
4.3.6 跟柯里化有什么区别 83
4.4 组合与管道 84
4.4.1 管道(Pipeline) 84
4.4.2 组合与管道 86
4.4.3 管道函数 87
4.5 小结 87
第5章 Macro宏 89
5.1 什么是REPL 89
5.1.1 宏扩展器(Macro Expander) 90
5.1.2 那么前端怎么办 92
5.2 为什么要语法糖 93
5.2.1 只是为了语法漂亮吗 94
5.3 Sweet.js 94
5.3.1 Rule Macro 95
5.3.2 Case Macro 97
5.4 Infix Macro 和 Operator 104
5.4.1 Infix Macro 104
5.4.2 自定义操作符 105
5.5 小结 106
第6章 模式匹配 107
6.1 Destructure 107
6.1.1 对象 109
6.1.2 数组 109
6.1.3 函数 109
6.2 Arity 函数 110
6.3 Fizz Buzz 111
6.3.1 字面匹配(Literal Matching) 111
6.3.2 绑定 113
6.3.3 Vector与Map匹配 113
6.3.4 Guard 114
6.3.5 Sparkler 114
6.4 代数数据类型(ADT) 116
6.5 小结 118
第7章 Monadic编程 119
7.1 链式调用 119
7.1.1 Promise 120
7.1.2 高阶Promise 122
7.2 Monad 123
7.2.1 函子(Functor) 123
7.2.2 Applicative Functor 126
7.2.3 含幺半群(Monoid) 130
7.2.4 Monad就是容器界的管道 132
7.2.5 Monad就是自函子范畴上的一个幺半群 136
7.3 走钢丝 139
7.3.1 用Monad表示薛定谔猫 139
7.3.2 皮尔斯走钢丝 140
7.4 Monad在JavaScript中的应用 143
7.4.1 Promise版本的走钢丝 144
7.4.2 When 144
7.5 Reactive编程 146
7.5.1 流(Stream) 146
7.5.2 Functor 147
7.5.3 Applicative 147
7.5.4 Monad 148
7.5.5 一个“简单”的Reactive实例 149
7.6 小结 153
第8章 并发编程 154
8.1 什么是并发 154
8.1.1 异步与多线程 155
8.1.2 JavaScript的并发模型 157
8.2 通信顺序进程(CSP) 160
8.3 使用Generator实现CSP 162
8.3.1 Generator 163
8.3.2 Go Block 163
8.3.3 timeout 164
8.3.4 take <! 165
8.3.5 put >! 165
8.3.6 JavaScript CSP版本的例子 166
8.4 实战 CSP 168
8.4.1 使用移植的core.async 168
8.4.2 使用ES7中的异步函数 169
8.4.3 try catch 170
8.5 小结 173
参考资料 174
4.2 柯里化有什么用
还记得上一章提到的提出柯里悖论的 Haskell Curry 吗?这里要说到的柯里化中的 柯里,完全不是巧合,确实就是 Haskell Curry 的姓。借助于利用他的名字命名的语言 Haskell,可以更好地理解柯里化。
在 Haskell 语言中,函数是会自动柯里化的:
max 3 4
其实就是:
(max 3) 4
可以看看 max 与 max 3 函数的类型:
ghci> :t max
max :: Ord a => a -> a -> a
看明白了吗?Ord a => 表示类型约束 a 为可以比较大小的类型,因此 max 的类型可以翻译成:当给定一个 a,会得到 a -> a,即接收一个 a 类型,返回一个 a 类型。接下来再看看 max 3 的类型就好理解了。
ghci> :t max 3
(Num a, Ord a) => a -> a
左侧表示类型约束 a 可以是 Ord 或者 Num,意思是 max 3 还是一个函数,如果给定一个 Ord 或者 Num 类型的参数,则返回一个 Ord 或者 Num 类型。
现在是不是清晰了?在Haskell中,每给定一个参数,函数如果是多参数的,该函数还会返回一个处理余下参数的函数。这就是自动柯里化。
而在 JavaScript(以及大多数语言) 中则不是这样的,如果给定多参函数的部分参数,函数会默认其他参数是 undefined ,而不会返回处理剩余参数的函数。
反正最后都要计算出值,那么柯里化和一次把所有约束添加上有什么区别呢?
再回到上一节的例子,还记得我们要编写一本能拿到所有男性姓名的操作手册吧。我们把_.filter 硬是改写成了柯里化版本的Rfilter,终于可以组合我们的操作手册了:
const getMaleName = _.compose(
data => _.map(data, d => d.name), // <1>
Rfilter(d => d.sex == 'male')) // <2>
getMaleName(data)
(1)对于还没有柯里化的_.map就只能说:提取数据的名字,这里的数据等于传入的数据。
(2)我可以明确地在手册里写:过滤出数据中性别为男性的。
对比这两行明显可以看出,第一行特别啰唆,就是因为把本来应该是自由变量的data当约束变量给了_.map函数。相反,Rfilter并不需要data这个自由变量,意义却完全一样,这种方式又叫作“Pointfree”或者“Pointless”。
而且,当柯里化_.filter函数之后,我们实际上得到的是两个函数,而不只是一个。给定一个约束后得到一个新的函数,这个函数就可以拿来组合其他函数,或者再给定不同约束返回不同给定值。
当可组合的函数越多,就能够越大程度地复用现有函数,组合出更多的函数。就像乐高积木,如果买一般的通用乐高,其实可以组合出各式各样的形状,但是一旦有些积木给了一些设定,比如你买了一盒辛普森一家的乐高(图4-1),就很难和生活大爆炸的乐高(图4-2)组合到一块去,因为其中很多积木都添加了一些设定,设定越多,则离抽象越远,离具体越近,也就越难复用。
1.看本书之前你要知道
1)最好能看懂JavaScript代码
这既不是一本介绍Clojure的书,也不是一本介绍JavaScript的书,而是一本介绍如何用JavaScript函数式编程的书。其中一些函数式的思想和表现形式都借用了Clojure,因此叫作Clojure 风格的函数式JavaScript,但是并不要求在读本书前会Clojure ,而只需要能阅读JavaScript代码。如果你会Clojure,则可以完全忽略我解释Clojure代码的段落,当然JavaScript的部分才是重点。
2)你可能买错书了,如果你
想学JavaScript
这不是一本JavaScript的教科书,这里只会介绍如何用JavaScript进行函数式编程,所以如果想要系统地学习JavaScript,则学习《JavaScript语言精粹》可能已经足够了。另外,如果读者的英文水平好的话,则还有一本可以在线免费阅读的JavaScript Allonge。
想学Clojure
同样,这也不是一本Clojure的教科书,只含有一些用于阐述函数式编程思想的Clojure代码。你确实可以学到一些Clojure编程知识,但很可能是非常零碎且不完整的知识。如果想要系统地了解和学习Clojure,则非常推荐你阅读The Joy of Clojure ,另外,如果读者英文比较好,还有一本可以免费在线阅读的CLOJURE for the BRAVE and TRUE也非常不错。
是函数式编程的专家
如果你已经在日常工作或学习中使用Scala、Clojure或者Haskell等函数式语言编程的话,那么本书对你在函数式编程上的帮助不会太大。不过:这本书对缓解你从函数式语言迁移到JavaScript编程的不适应该是非常有效的。这也正是本书的目的之一。
2.准备环境
在开始阅读本书之前,如果你希望能运行书中的代码,可能需要一些环境的配置。而且书中的所有源码和运行方式都可以在本书的Github仓库 中找到。当然如果你使用Emacs(同时还配置了org babel的话)阅读本书的源码,对于大部分代码只需要光标放在代码处按c-c c-c即可。
JavaScript
原生的JavaScript没有什么好准备的,可以通过Node或者Firefox(推荐)的Console运行代码。当然第5章会有一些使用Sweet.js写的Macro,这则需要安装Sweet.js。
– 安装Node/io.js
(1)下载Node.js。
(2)如果使用Mac,可以直接用Brew安装。
brew install node
# 或者
brew install iojs
– 安装Sweet.js
在安装完Node.js之后在命令行输入:
npm install -g sweet.js
Clojure
书中的Clojure代码大都用来描述函数式编程的概念,当然如果想要运行书中的 Clojure 代码,首先需要安装JVM或者JDK ,至少需要1.6版本,推荐安装1.8版本。
– 安装 leiningen
leiningen是Clojure的包管理工具,类似于Node的Npm、Ruby的bundle、Python的pip。另外leiningen还提供脚手架的功能。可以通过官网的脚本安装 。Mac用户可以简单地使用brew install leiningen安装。
安装完成之后,就可以运行lein repl,打开repl,试试输入下列Clojure代码,你将会立马看见结果。
(+ 1 1)
;=> 2
– 编辑器
如果更喜欢使用编辑器来编辑更长的一段代码,我推荐非Emacs用户使用Light Table ,Intellij用户则使用cursive 。当然如果读者已经在使用Emacs,那就更完美了,Emacs cider mode 是Clojure编程不错的选择。
3.本书中的代码
书中的所有源码和运行方式都可以在本书的Github仓库 中找到,书中几乎所有的例子都以测试的形式完成。
4.反馈
如果你是开源贡献者,那么应该很习惯通过Github Issue9提交任何反馈,如果是Pull Request,那就更好了。当然如果没有使用过Github Issue也没有关系,这里 有非常详细的教程。
5.代码风格约定
本书的JavaScript代码都遵循Airbnb JavaScript Style Guide 中的ES5和React的风格约定。
6.本书的组织结构
第1章
将介绍JavaScript的基本函数式背景,简要地介绍为什么要关心函数式编程,为什么说Underscore不够函数式,JavaScript要作为完整的函数式语言还缺些什么?
第2章
主要介绍Clojure的集合数据结构。这是个无聊但是又很重要的章节,可以说函数式编程最基本、最重要的就是集合操作。本章会涉及如何操作集合、惰性求值与惰性序列。
第3章
在了解了持久性数据结构后,我们可能会产生疑惑,如果数据结构都是不可变的,那么循环该怎么写呢?本章就是要解开各种使用不可变数据结构的疑惑,用这些不可变数据结构可以切换一种编程的思维方式。
第4章
Underscore并不利于函数组合,但是函数组合其实是函数式编程最重要的思想。在这一章里面,我会详细介绍为什么说Underscore错了,而为什么要喜欢上柯里化,以及Clojure 1.7新推出的Transducer又是如何帮助我们更容易组合出更高效的函数的。
第5章
我特别不情愿把Macro翻译成宏。宏特别容易让人以为是 C 语言里面那个#define宏,虽然都是宏,但其实那里跟这里说的Macro不是一个级别的。Macro是Lisp语言之所以特别的原因之一。本章我们就来看看到底什么是、为什么,以及如何在JavaScript中使用Macro。
第6章
这里说的模式匹配包括两种:一种是按位置或者key匹配集合,取出相应数据。另一种是Haskell风格的对函数参数的模式匹配。本章篇幅比较小,因为模式匹配并不是Clojure(也不是JavaScript)的主要模式,尽管在一些有强大类型系统的函数式语言(Scala、Haskell)中比较重要。
第7章
Monad这个范畴论里出来的神秘玩意,但你可能没有在意,其实这在前端世界早都被玩腻了。本章将会介绍Monad和它的朋友们,并且将带你体验JavaScript的Promise,以及Reactive编程。
第8章
并发编程一直是令人头疼的编程方式,直到Clojure和Go的出现,彻底改变了我们并发编程的方式。而对于单线程的JavaScript,基于事件循环的并发模型也一直困扰着我们,到底能从Clojure学些什么,可以使我们的前端并发编程之路更顺畅一些呢?本章将带你熟悉并发、JavaScript的并发模型,以及CSP并发模型。
7.本书使用的约定
本书使用以下字体排版约定。
1)楷体
表示新的术语。
2)等宽字体
代码清单,出现在段落之内则表示变量、函数名、关键字等。
3)粗体
重点概念。
4)下画线
需要填入的词,我可能已经帮大家填上了。
5)横线
可以忽略的词。
前端函数式攻城指南 下载 mobi pdf epub txt 电子书 格式 2024
前端函数式攻城指南 下载 mobi epub pdf 电子书不错?
评分书很好,对函数式编程解释的很到位,通俗易懂
评分不错 挺好的
评分不错?
评分14
评分睡前读物,讲得不是很高深,不烧脑,催眠刚好……
评分基本看完了,作者举例很生动的
评分和同学一起买的,很不错的书? ?(?¯???¯???)?”
评分好好 快速 便捷
前端函数式攻城指南 mobi epub pdf txt 电子书 格式下载 2024