什么是函数响应式编程?

版权声明:转载请标明原作者 https://blog.csdn.net/pf_frontWord/article/details/88637943

什么是函数响应式编程?

响应式编程思想为体,函数式编程思想为用。首先我们要来了解什么是函数式编程和响应式编程。

什么是函数式编程?

顾名思义,函数式编程就是用函数来解决问题的编程方式,几乎任何一门语言都支持函数,但是函数式编程具有几个特点:

  1. 声明式(Declarative)
  2. 纯函数(Pure Functio
  3. 数据不可变性(Immutability)

在深入了解这三个特点之前,我们需要知道JavaScript是不是函数式编程?
有的语言生来就是函数式编程,比如Haskell、Lisp这些语言本身就强制要求代码遵从以上三个要求,不过JavaScript并没有要求数据不可变性,也就是说用JavaScript写的函数并不能保证没有任何副作用。

那到底javascript是不是函数式编程?

从语言的角度上讲,JavaScript当然不算一个纯粹意义上的函数式编程语言,但是JavaScript的函数具有第一公民的身份,因为函数本身就是一个对象,可以被赋值给一个对象也可以作为一个参数传递,可以很方便的应用函数式编程的思想。虽然javascript不算纯粹意义上的编程语言,但是通过一些编程规范和一点工具的帮助,完全可以写出函数式的代码。
RxJs就是辅助我们写出函数式代码的一种工具。 接下来,我们分别介绍JavaScript如何满⾜函数式编程的特性需要。

声明式

和声明式相对应的编程⽅式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的⼀种编程⽅式。
先来看⼀个命令式编程的例⼦,我们要实现⼀个功能,将⼀个数组中每个元素的数值乘以2。这样⼀个功能可以实现为⼀个叫double的函数,代码如下:

function double(arr) {
	const results = [];
	for (let i = 0; i < arr.length; i++){
		results.push(arr[i] * 2)
	};
	return results;
};

代码解析:

  1. 创建一个results的空数组
  2. 创建一个for循环,然后每次把arr数组的每一个值乘2,再利用push方法添加到results中
  3. 返回 results数组

这个double函数的实现没有任何⽑病,但是,我们又来了⼀个需求:实现⼀个函数,能够把⼀个数组的每个元素加⼀。
我们可以再实现⼀个addOne函数,代码如下:

function addOne(arr) {
	const results = [];
	for (let i = 0; i < arr.length; i++){
		results.push(arr[i] + 1)
	};
	return results;
};

如果比较一下double和addOne这两个函数,发现除了函数名和push的参数不一样之外其余的代码都是一样的,这就出现了重复代码的问题(重复代码可能是所有软件中邪恶的根源)。我们可以看到命令式编程的一个大问题,我们应该改进它。
我们可以利用javascript中的map方法,来重新实现double和addOne函数,代码如下:

function double(arr) {
	return arr.map(function(item) {return item * 2});
}
function addOne(arr) {
	return arr.map(function(item) {return item + 1});
}

代码简洁了很多,没有了for循环,也没有了push的操作,因为这些都被封装在map方法里了。map方法主要提供了一个函数类型的参数,这个参数可以定制对每一个数组元素如何处理。我们来看double中这个定制函数,代码如下:

function(item) {return item * 2};

这个函数实现了这样⼀个功能:不管传⼊什么数据,都会返回这个数据乘以2的结果。这就是声明式编程,因为在double函数中,代码实际上是这样⼀种解读:把⼀个数组映射(map)为另⼀个数组,每个对应的元素都乘以2。我们可以把上面的代码通过es6的箭头函数再做一次优化,代码如下:

const double = arr => arr.map(item => item * 2);
const addOne = arr => arr.map(item => item + 1);

这就是声明式编程,比命令是编程更容易维护,代码更简洁,更具有表现力。

纯函数

还是以上面提到的double函数为例,这一次我们从使用者的角度来看,代码如下:

const oneArray = [1, 2, 3];
const anotherArray = double(oneArray);
// anotherArray的内容为[ 2, 4, 6 ]
// oneArray的内容依然是[ 1, 2, 3 ]

我们先声明⼀个oneArray,然后将oneArray作为参数传递给double函数,返回的结果赋值给anotherArray,因为double的实现遵从了保持数据不可改的原则,所以oneArray数组依然是以前的值,⽽anotherArray是⼀个全新的数组,这两个数组中的数据相互独⽴,互不⼲扰。所以,我们说double就是⼀个“纯函数”。所谓纯函数,指的是满⾜下⾯两个条件的函数:

  • 函数的执行过程由参数决定,不会受除参数之外的任何数据影响。
  • 函数不会修改任何外部状态,比如修改全局变量传入的参数。

表⾯上看起来,纯函数的要求,是限制了我们编写函数的⽅式,似乎让我们没法写出“更强⼤”的函数,实际上,这种限制带来的好处远远⼤于所谓“更强⼤”的好处,因为,纯函数让我们的代码更加简单,从⽽更加容易维护,更加不容易产⽣bug。
我们还是通过⼀段代码例⼦来说明,代码如下:

function arrayPush (arr, newValue) {
	arr.push(newValue);
	return arr;
}
const originalArray = [1, 2, 3];
const pushedArray = arrayPush(originalArray, 4);
const doubledPushedArray = double(pushedArray);
// pushedArray值应该是[ 1, 2, 3, 4 ]
// doubledPushedArray值应该是 [ 2, 4, 6, 8 ]

当上⾯的语句执⾏完毕之后,originalArray的值却是[ 1, 2, 3, 4 ],为什么呢,因为push的操作会改变原数组,也就是说会改变传递过来的参数originalArray 数组。而函数式编程的一个条件就是不能修改任何外部状态,所以我们不能使用push操作,但是我们可以用es6的扩展运算符…达到纯函数的条件 ,代码如下:

function arrayPush (arr, newValue) {
	return [...arr, newValue];
}

和纯函数相反的就是“不纯函数”(Impure Function),⼀个函数之所以不纯,可能做了下⾯这些事情:

  • 改变全局变量的值。
  • 改变输⼊参数引⽤的对象,就像上⾯不是纯函数的arrayPush实现。
  • 读取⽤户输⼊,⽐如调⽤了alert或者confirm函数。
  • 抛出⼀个异常。
  • 操作浏览器的DOM。
  • ⽹络输⼊/输出操作,⽐如通过AJAX调⽤⼀个服务器的API。

上⾯还只是不纯函数的⼀部分表现,其实,有⼀个很简单的判断函数纯不纯的⽅法,就是假设将⼀个函数调⽤替换为⼀个预期返回的常数,程序运⾏结果是否一样。

数据不可变

程序要好发挥作⽤当然是要产⽣变化的数据,但是并不意味着必须要去修改现有数据,替换⽅法是通过产⽣新的数据,来实现这种“变化”,也就是说,当我们需要数据状态发⽣改变时,保持原有数据不变,产⽣⼀个新的数据来体现这种变化。
不可改变的数据就是Immutable数据,它⼀旦产⽣,我们就可以肯定它的值永远不会变,这⾮常有利于代码的理解。在JavaScript中,字符串类型、数字类型就是不可改变的数据,使⽤这两种类型的数据给你带来的⿇烦⽐较少。相反,JavaScript中⼤部分对象都是可变的,⽐如JavaScript⾃带的原⽣数组类型,数组的push、pop、sort函数都会改变⼀个数组的内容,由此引发的bug可不少。这些不纯的函数导致JavaScript天⽣不是⼀个纯粹意义上的函数式编程语⾔。

什么是响应式编程?

响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。如果你使⽤过Excel的公式功能,你就已经应⽤过响应式编程。再例如,在命令式编程环境中,a:=b+c表示将表达式的结果赋给a,而之后改变b或c的值不会影响a。但在响应式编程中,a的值会随着b或c的更新而更新。
  响应式编程最初是为了简化交互式用户界面的创建和实时系统动画的绘制而提出来的一种方法,但它本质上是一种通用的编程范式。例如,在MVC软件架构中,响应式编程允许将相关模型的变化自动反映到视图上,反之亦然。

猜你喜欢

转载自blog.csdn.net/pf_frontWord/article/details/88637943