翻译: 安歌
什么是函数式编程
- 在计算机科学中,函数式编程是一种编程范式
- 函数式编程把计算看作是对数学函数的求值
- 函数式编程避免了改变状态和易变数据
其他主流的编程范式
- 面向过程编程
- 面向对象编程
- 元编程
- 命令式编程
- 声明式编程
面向过程编程建立在过程调用的概念之上,包含了一系列的待执行的计算步骤。任何给定的过程都可以在程序执行期间被调用,包括其他或自身的程序。主要的面向过程的编程语言有COBOL、BASIC、C、ADA、GO。
面向对象编程建立在对象的概念之上,包含了属性和方法。这种模式更接近函数式编程。主要的面向对象的编程语言有C++、Java、PHP、C#、Python、Ruby、Swift等。
元编程把程序作为它们的数据,这意味着一个程序可以被设计成在运行时读取、生成、分析或转换其他程序,甚至对自己进行修改。
命令式模式 VS 声明式模式
- 命令式模式侧重于描述程序如何运行(怎么做),它由程序执行的命令组成;
- 声明式模式侧重于描述程序要达成什么效果(做什么),并没有指定程序应该如何实现。
var books = [
{name:'JavaScript', pages:450},
{name:'Angular', pages:902},
{name:'Node', pages:732}
];
/* 命令式编程 */
for (var i = 0; i < books.length; i++) {
books[i].lastRead = new Date();
}
/* 声明式编程 */
books.map((book)=> {
book.lastReadBy = 'me';
return book;
});
console.log(books);
复制代码
- 在上面的代码片段中,我使用两种不同的方式给
Books
里面的每一个对象新增属性:lastReadBy
; - 第一种方式使用了
for
循环,通过数组下标为每一个元素新增属性。因此,这种程序的焦点在于如何操作以达到期望的输出; - 第二种方式使用了原生JavaScript里数组的
map()
方法,这个方法接收一个函数作为参数并对容器中的每一个元素执行调用。这种代码描述的是要做什么而不是怎么做,实际的操作则由map()
负责。
数学函数还是纯函数?
在数学上,函数是一组输入和一组对应输出间的关系,它的特点是每一个输入组合都只有一个确切的输出。
在函数式编程中,这类函数称作纯函数,它只依赖与函数接收到的输入数据,除了返回结果外,不会改变输入的数据。
Math.random()
不是纯函数,因为它的每一次调用都可能返回不同的值。
Math.min(1,2)
是纯函数,因为对于给定的一组输入它总是返回相同的输出。
为什么要函数式编程
- 纯函数特性保证了其作用域之外的变量不会被更改
- 降低了复杂性,我们只需要关注程序要做什么而不是怎么做
- 代码更易测试,结果更易验证,因为它不依赖程序的状态
- 代码的可读性更强
- 代码更易理解
函数式编程的例子
Array 函数
filter()
负责“程序如何执行”,我们只关注输入(
meetups
数组)以及输出(
activeMeetupsFP
),但在第一种方式中我们还需要关心如何使用
for
循环进行操作。
类似的,下面数组的其他方法,也有助于我们实现函数式编程并降低代码的复杂性:
- find
- map
- reduce
- every
- some
函数链
它是一种调用多个方法的调用机制,通过函数返回一个对象的方式使得每一个方法的调用可以链接在一个语句中,而不需要临时变量存储中间结果值。
支持FP的库
这是一些提供了很多实用函数使得代码更具声明性的第三方库:
- RamdaJS
- UndersoreJS
- lodash
副作用
如果一个程序或表达式会修改其作用域之外的程序状态,或者除了返回值之外,对调用它的函数有任何其他可见的干扰,那么我们称其是有副作用的。
scheduleMeetu
p的实际职责是给meetup对象添加
date
和
place
属性,但它却又修改了
isActive
的值,而这个属性是被其他函数如
publishMeetup
所依赖的。作为副作用,
publishMeetup
得不到期望的输出,因为它的输入在这期间已经发生了改变。在大型程序(真是程序)中,副作用是很难被调试的。
不可变性
为确保函数不会更改原始数据而不是操作后返回数据的新副本,不变形显得尤为重要。
想象一下如果数组和对象在多个函数之间传递,而我们不去维护不变性,那么函数可能无法获取数组和对象的原始副本。
在易变对象和数组上发生错误是很难调试的。
易变性并不是没有用处,但应该在必要的时候才使用。
支持不变性的库
JavaScript默认不提供任何保证对象和数组不可变的限制,这里有一些库可以帮助我们实现不变性:
- Seamess-immutable
- ImmutableJs
总结
函数式编程的主要特征就是纯函数、不可变性和无副作用。
如果你喜欢这篇推文并觉得有帮助,请帮忙点个赞,谢谢!