RxJS 函数式与响应式编程

栏目: JavaScript · 发布时间: 6年前

内容简介:简单说,”函数式编程”是一种所谓函数赋值给变量:

简单说,”函数式编程”是一种 “编程范式” (programming paradigm),也就是如何编写程序的方法论。

函数式编程基本要素

所谓 “一等公民” (first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为其它函数的返回值。

函数赋值给变量:

const greet = function(msg) { console.log(`Hello ${msg}`); }
greet('Semlinker'); // Output: 'Hello Semlinker'

函数作为参数:

const logger = function(msg) { console.log(`Hello ${msg}`); };
const greet = function(msg, print) { print(msg); };
greet('Semlinker', logger);

函数作为返回值:

const a = function(a) {
  return function(b) {
    return a + b;
  };
};

const add5 = a(5);
add5(10); // Output: 15

函数式编程重要特性

  1. 只用表达式,不用语句

“表达式”(expression)是一个单纯的运算过程,总是有返回值;”语句”(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。

  1. 纯函数

纯函数的特点:

  • 给定相同的输入参数,总是返回相同的结果。
  • 没有依赖外部变量的值。
  • 没有产生任何副作用。

纯函数的示例:

const double = (number) => number * 2;
double(5);

非纯函数示例:

Math.random(); // => 0.3384159509502669
Math.random(); // => 0.9498302571942787
Math.random(); // => 0.9860841663478281

所谓 “副作用” )(side effect),是指函数内做了与本身运算无关的事,比如修改某个全局变量的值,或发送 HTTP 请求,甚至函数体内执行 console.log 都算是副作用。 函数式编程强调函数不能有副作用,也就是函数要保持纯粹,只执行相关运算并返回值,没有其他额外的行为

函数式编程的优势

  1. 代码简洁,开发快速

函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快。

  1. 接近自然语言,易于理解,可读性高

函数式编程的自由度很高,可以写出很接近自然语言的代码。我们可以通过一系列的函数,封装数据的处理过程,代码会变得非常简洁且可读性高,具体参考以下示例:

[1,2,3,4,5].map(x => x * 2).filter(x => x > 5).reduce((p,n) => p + n);
  1. 可维护性高、方便代码管理

函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合。

  1. 易于 “并发编程”

函数式编程不需要考虑”死锁”(deadlock),因为它不修改变量,所以根本不存在”锁”线程的问题。不必担心一个线程的数据,被另一个线程修改,所以可以很放心地把工作分摊到多个线程,部署”并发编程”(concurrency)。

JavaScript 函数式编程常用方法

  1. forEach

在 ES 5 版本之前,我们只能通过 for 循环遍历数组:

var heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
for (var i =0, len = heroes.length; i < len; i++) {
  console.log(heroes[i]);
}

在 ES 5 版本之后,我们可以使用 forEach 方法,实现上面的功能:

var heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
heroes.forEach(name => console.log(name));
  1. map

在 ES 5 版本之前,对于上面的示例,如果我们想给每个英雄的名字添加一个前缀,但不改变原来的数组,我们可以这样实现:

var heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
var prefixedHeroes = [];
for (var i =0, len = heroes.length; i < len; i++) {
  prefixedHeroes.push('Super_' + heroes[i]);
}

在 ES 5 版本之后,我们可以使用 map 方法,方便地实现上面的功能:

var heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
var prefixedHeroes = heroes.map(name => 'Super_' + name);
  1. filter

在 ES 5 版本之前,对于 heroes 数组,我们想获取名字中包含 m 字母的英雄,我们可以这样实现:

var heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
var filterHeroes = [];
for (var i =0, len = heroes.length; i < len; i++) {
  if(/m/i.test(heroes[i])) {
    filterHeroes.push(heroes[i]);
  }
}

在 ES 5 版本之后,我们可以使用 filter 方法,方便地实现上面的功能:

var heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
var filterRe = /m/i;
var filterHeroes = heroes.filter(name => filterRe.test(name));

响应式编程

什么是响应式编程

响应式编程就是用异步数据流进行编程,这不是新理念。即使是最典型的点击事件也是一个异步事件流,从而可以对其进行侦测(observe)并进行相应操作。

可以基于任何东西创建数据流。流非常轻便,并且无处不在,任何东西都可以是一个流:用户输入、缓存、数据结构等等。例如,想象一下微博推文也可以是一个数据流,和点击事件一样。你可以对其进行侦听,并作相应反应。

Reactive Extension

Rx(Reactive Extension)的概念最初由微软公司实现并开源,也就是 Rx.NET,因为 Rx 带来的编程方式大大改进了异步编程模型,在 .NET 之后,众多开发者在其他平台和语言上也实现了 Rx 的类库。比如有 Java 实现的 RxJava,C++ 实现的 RxCpp,用 Python 实现的 RXPy,当然也包括我们后面要学习的 JavaScript 实现的 RxJS。

虽然 Rx 的主要目的是解决异步问题,按并不表示 Rx 不适合同步处理数据。实际上,在使用 Rx 后,我们开发者可以不用关心代码是被同步执行还是异步执行,所以处理起来会更加简单。

非响应式与响应式

说了那么多响应式的概念,我们来看一下非响应式的一个例子:

let a1 = 6;
let b1 = 6;
let c1 = a1 + b1;

上面的示例很简单,很明显 c1 的值为 12。但当我改变 a1 的值,比如改为 3 时,我们会发现 c1 的值并不会更新。同理,单独改变 b1 的值,c1 的值也不会更新。如果要获取新的值的话,我们就需要重新计算。

其实,在生活中也有对应的场景。比如商城购物车,当我们改变购物车的商品数量或者删除某个商品时,我们希望能自动更新订单金额,而不需要用户做任何其他操作。

而生活中响应式的另外一个常见例子就是 Excel 表格,以上面的例子为例,A1 单元格的值为 6,B1 单元格的值也为 6,C1 单元格的值为 a1 + b1 。 当我们改变 A1 单元格或 B1 单元格的值时,你会发现 C1 单元格内的值会自动更新,而不需要我们手动执行更新操作,我们可以简单的理解,这就是响应式。

在前端领域,我们经常要跟异步场景打交道。比如 DOM 事件、AJAX、WebSocket、定时器等。通常情况下,异步的场景会比较复杂。不过值得庆幸地是,我们拥有 RxJS 这个利器。RxJS 擅长处理异步操作,因为它对数据采用 “Push”(相较于 “Pull” 方式),当一个数据产生的时候,会被主动地推给处理函数,这个处理函数不用关心数据是同步或者异步产生的,这样就让开发者从异步处理的境遇中解救出来。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入理解TensorFlow:架构设计与实现原理

深入理解TensorFlow:架构设计与实现原理

彭靖田、林健、白小龙 / 人民邮电出版社 / 2018-5-1 / 79.00元

本书以TensorFlow 1.2为基础,从基本概念、内部实现和实践等方面深入剖析了TensorFlow。书中首先介绍了TensorFlow设计目标、基本架构、环境准备和基础概念,接着重点介绍了以数据流图为核心的机器学习编程框架的设计原则与核心实现,紧接着还将TensorFlow与深度学习相结合,从理论基础和程序实现这两个方面系统介绍了CNN、GAN和RNN等经典模型,然后深入剖析了TensorF......一起来看看 《深入理解TensorFlow:架构设计与实现原理》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具