第一章 函数式编程起步——若干问题
函数式编程(或 FP
)早在计算机时代初期就已经诞生了。由于它越来越多地应用于多个框架和工具库,尤其是 JavaScript
(JS
) 相关领域,函数式编程正经历着某种意义上的复兴。本章主要内容有:
- 介绍函数式编程的相关概念,对其有个初步认识;
- 使用函数式编程带来的好处(及问题),以及为什么要使用它;
- 考察
JavaScript
适合进行函数式编程的原因; - 回顾必要的
JS
特性与常用工具,以全面掌握本书各知识点。
学完本章,您将习得本书后续章节会用到的基本工具。首先来了解一下函数式编程。
1. 何谓函数式编程?What is functional programming?
回顾一下计算机发展史,您会发现仍在使用的第二古老的编程语言 Lisp
,就是以函数式编程为基础的。此后,函数式语言层出不穷,函数式编程的应用也更加广泛。但即便如此,如果问大家什么是函数式编程,您可能会得到两种截然不同的回答。
小知识
对于喜欢打破砂锅问到底的人或爱好历史掌故的发烧友而言,目前仍在使用的最古老的语言是
Fortran
,它出现于 1957 年,比Lisp
早一年。 在Lisp
之后不久,出现了另一种长期存在的语言COBOL
,用于面向业务的编程。
取决于询问的人,您要么听到这样的回答:函数式编程是一种现代的、先进的、开明的编程手法,其他编程范式在它面前都会黯然失色;要么听到另一种声音:函数式编程基本上还是一个理论的产物,其复杂程度超过了带来的好处,在现实世界中几乎不可能实现。实际上,真正的答案,同往常一样,并不是非黑即白地走极端,而是介于这两者之间。我们不妨从理论与实践的对比出发,看看应该如何使用函数式编程。
1.1. 理论与实践 Theory versus practice
本书不会对函数式编程作理论上的深入探讨,而是重点展示如何将函数式编程的一些技术和原则成功应用于日常的 JavaScript
编程中。本书也不会教条式地行文,而是从实用的角度展开话题。我们既不会因为某些有用的 JavaScript
结构不符合函数式编程的学术要求而绕开它们,也不会仅仅为了迎合函数式的编程范式而避开一些实用的 JavaScript
特性。事实上,本书毋宁说是在介绍 类函数式编程(SFP
, Sorta Functional Programming),因为书中的代码将会是 函数式编程特性、更为经典的 命令式编程、以及 面向对象编程(OOP)三者的结合体。
即便如此,本书也并非将所有的理论知识都搁置一旁。书中会有侧重地论述函数式编程的主要观点,介绍一些相关术语和基本定义,并对函数式编程的核心概念作重点阐释。我们将始终本着产出务实高效的 JavaScript
代码的初衷,而不是一味追求一些晦涩难懂的、教条式的函数式编程规范。
在编写大型程序和系统、以及开发清爽且可扩展的应用程序架构时,面向对象编程已经成为应对其固有复杂度的一种解决方案;一方面,随着当今 Web
应用程序的持续扩展,所有项目代码的复杂度都在不断增加;另一方面,JavaScript
的新特性甚至使得几年前几乎不可能实现的应用程序开发成为了可能:例如使用 Ionic
、Apache Cordova
或 React Native
制作的移动端(混合端)应用程序,或使用 Electron
或 NW.js
制作的桌面应用程序。时至今日,JavaScript
已经通过 Node.js
试水后端开发,该语言的使用范围正以一种严肃认真的方式不断扩大,以应对现代设计带来的复杂性。
1.2. 换一种方式思考 A different way of thinking
函数式编程是另一种编程方式,学起来可能还会比较吃力。在大多数语言中,编程往往是以命令式的方式进行的。程序是一系列以规定方式执行的语句,通过创建对象并操作它们来实现预期的结果,这通常意味着修改对象本身。而函数式编程则是基于特定的表达式求值来得到想要的结果。这些表达式由组合在一起的 函数 构建而成。在函数式编程中,常见的操作有函数传递(pass functions around,将函数作为另一个函数的参数传入,或者将一个函数作为原函数的计算结果返回)、不使用循环(not use loops,替之以递归)、以及跳过副作用(skip side effects,修改对象或全局变量本身)等等。
换言之,函数式编程聚焦的是该实现什么,而非怎样实现。您无需担心循环和数组的问题,而是在更高层面上考虑需要完成的任务。一旦习惯了这种风格,您的代码将变得更简洁优雅,并且可以轻松付诸测试及调试。但是,也不要落入以函数式编程为终极目标的陷阱!与其他软件工具一样,函数式编程仅仅是解决问题的一种手段而已。有时候函数式风格的代码未必就是好代码。正如任何技术一样,用函数式编程的思想写出糟糕的代码也是极有可能的!
1.3. 函数式编程不是什么?What FP is not
前面介绍了函数式编程 是什么,这里有必要澄清一些常见的误区,看看函数式编程 不是什么——
- 函数式编程不是形而上学的产物:诚然,由 Alonzo Church 于 1936 年提出的 lambda 算子 确实是证明理论计算机科学(比现代计算机语言的出现早 20 多年)重要成果的工具,函数式编程也以此为基础;然而如今的函数式编程语言已经在各种系统比比皆是;
- 函数式编程不是面向对象编程的反面:声明式与命令式风格不必非得二选一,也可以根据喜好进行混搭,就像本书中即将论述的那样,将所有的最佳实践结合到一起;
- 函数式编程学起来并不复杂:一些函数式编程语言与
JavaScript
有很大不同,但差异主要体现在语法层面。一旦了解基本概念,您就会发现在JavaScript
中也能殊途同归地得到相同的结果。