H5W3
当前位置:H5W3 > 其他技术问题 > 正文

函数式编程(一)-概述

函数式编程是一种编程范式,也就是如何编写程序的方法论,其它的编程范式还有面向对象编程,过程化编程等。函数式编程并不是一个新兴的概念,而是一个存在久远的概念,随着React的兴起,函数式编程的概念又火了起来,Rxjs、lodash等库都使用了函数式编程的思想。

这个系列会从什么是函数式编程说起,讨论函数式编程的优缺点,如何使用函数式编程编写优雅的代码,最后会探讨函数式编程在Javascript中的一些最佳实践。

1. 初窥函数式编程

解释什么是函数式编程并不是个容易的事情,我也是在尝试着学习和理解。函数式编程不是用function来编程,而是一种如何使用function,才能使它具备函数式的一种方法。要了解怎么使用函数,首先我们需要了解什么是函数。

1.1 函数

这里简单回顾一下初中的数学知识,当我们看待一个函数时,它可能长这样 y = f(x) f(x) = 2x2 + 3 可以看出函数的基本特点在于它有一个或多个输入值,并进行一定的计算,并且得到一个返回值。函数式编程中有一个术语叫做态射,来描述输入值和输出值的关系。

这里简单讨论下函数和程序的区别,这也是函数式编程的一大特性。程序是一系列指令的集合,它可能有输入值也可能没有,它可能有输出值也可能没有。而函数是接收输入值并通过计算返回输出值。

函数式编程的一大特点就是我们应该尽量的使用函数而非程序,当然在实际的开发中我们不可避免的要进行I/O操作,但是如果你的计划是使用函数式编程,那么在开发中就应该尽可能多的使用函数,而不是程序。

1.2 函数是一等公民(first class)

这是函数式编程的一个重要概念,函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。

Javascript本身不是纯的函数式编程语言,可以说是一个多范式的编程语言,但是由于其函数是一等公民特性,我们可以把函数作为参数进行传递,也可以将函数作为函数的返回值等特性,使得Javascript可以进行函数式编程。

同时这个特性是函数式编程的一些核心内容,比如闭包、高阶函数、柯里化等特性的基础

1.3 引用透明性

回到上面那个函数,根据其输入输出的值,可以形成如下的图像:

通过这个图我们可以得出两个结论:1. 函数一定有输入和输出值。 2. 函数对于相同的输入值返回相同的输出值,这个特性称为引用透明性。

引用透明性带来的巨大好处在于并发代码和结果可缓存,并发的问题在于对于全局变量的使用,需要引入锁机制来管理全局变量的使用,但是引用透明性只依赖入餐,所以线程可以自由运行。结果的可缓存也是显而易见的,对于一个输入其对应的输出也是唯一的。所以该输入的结果是可以缓存的。

1.4 纯函数

在引用透明性的基础上我们可以定义纯函数,纯函数具有引用透明性,同时任何外部变量不会影响函数内部运算的结果,同时函数内部的运算也不会影响到外部变量的值。

纯函数给我们带来的好处在于代码的可测试性的增强,当我们测试一个函数时,我们会用输入和期望的正确输出值来验证一个函数的正确性,但是当多次测试通过之后,是否就可以说我们的函数是正确的,这个是不一定。如果外部的变量被应用在了函数的运算中,那么当外部变量发生改变时,函数的计算结果也会变得不符合预期。同理,函数改变外部的值也会导致代码的无法测试。

1.5 声明式编码

与声明式编码相对应的是命令式代码,意思就是,我们通过编写一条又一条指令去让计算机执行一些动作,这其中一般都会涉及到很多繁杂的细节。

而声明式就是,我们通过写表达式的方式来声明我们想干什么,而不是通过一步一步的指示。

举个遍历的例子,命令式编程的写法是:

var array = [1,2,3];
for(var i = 0; i < array.length; i++){   console.log(array[i])
} 

而声明式的写法是:

array = [1, 2, 3];
array.forEach((item) => { console.log(item); }) 

声明式的好处在于代码的编写更清晰简洁,在forEach函数为纯函数的前提下,我们不用关心函数的内部是如何实现的,开发者只需要关注眼前的事情。

2.函数式编程的优势

函数式编程根据上述的几个特性,具有以下几个优势:1. 代码的可读性更强 2. 代码的可测试性更强 3. 易于编写可缓存的代码 4. 易于并发 

2.1 代码的可读性

由于函数式编程采用声明式的代码,所以代码的可读性更强,举个例子,当我们进行一个这样(1 + 2) * 3 - 4的计算时,我们可能会写成subtract(multiply(add(1,2), 3), 4),对其进行声明式的改造 add(1,2).multiply(3).subtract(4)这样我们就可以直观的看出这句表达式的含义了。

2.2 代码的可测试性

这个优势是纯函数带来的,函数与外部变量的隔离使得测试只用关心函数内部逻辑,更易进行单元测试。

2.3 可缓存和可并发编程

这两个优势是函数的引用透明性带来的,这里不再赘述。

3.总结

首先清楚地理解什么是函数:它不仅仅是一个语句或者操作的集合,而且需要一个或多个输入(理想情况下只需一个!)和一个输出。

函数是一等公民的这个特性是函数式编程的很多特性的基础,也是Javascript语言函数式编程的基础。

引用透明性和纯函数使得函数更加易于测试,同时更易于并发编程和函数的缓存。

声明式表达使得函数更易理解。

下一章我们会开始讨论如何使用函数式的思想进行编程。

本文地址:H5W3 » 函数式编程(一)-概述

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址