30 天精通 RxJS (02): Functional Programming 基本观念

什麽是 Functional Programming ?

Functional Programming 是一种编程范式(programming paradigm),就像 Object-oriented Programming(OOP)一样,就是一种写程式的方法论,这些方法论告诉我们如何思考及解决问题。

简单说 Functional Programming 核心思想就是做运算处理,并用 function 来思考问题,例如像以下的算数运算式:

(5 + 6) - 1 * 3

我们可以写成

const add = (a, b) => a + b
const mul = (a, b) => a * b
const sub = (a, b) => a - b

sub(add(5, 6), mul(1, 3))

我们把每个运算包成一个个不同的 function,并用这些 function 组合出我们要的结果,这就是最简单的 Functional Programming。

Functional Programming 基本要件

跟 OOP 一样不是所有的语言都支持 FP,要能够支持 FP 的语言至少需要符合函式为一等公民的特性。

函式为一等公民 (First Class)

一等公民就是指跟其他资料型别具有同等地位,也就是说函式能够被赋值给变数,函式也能够被当作参数传入另一个函式,也可当作一个函式的回传值

函式能够被赋值给变数

var hello = function() {}

函式能被当作参数传入

fetch('www.google.com')
.then(function(response) {}) // 匿名 function 被传入 then()

函式能被当作回传值

var a = function(a) {
    return function(b) {
      return a + b;
    }; 
    // 可以回传一个 function
}

Functional Programming 重要特性

Expression, no Statement

Functional Programming 都是 表达式 (Expression) 不会是 陈述式(Statement)。
基本区分表达式与陈述式:

表达式 是一个运算过程,一定会有返回值,例如执行一个 function

add(1,2)

  • 陈述式 则是表现某个行为,例如一个 赋值给一个变数
a = 1;

有时候表达式也可能同时是合法的陈述式,这裡只讲基本的判断方法。如果想更深入了解其中的差异,可以看这篇文章 Expressions versus statements in JavaScript

由于 Functional Programming 最早就是为了做运算处理不管 I/O,而 Statement 通常都属于对系统 I/O 的操作,所以 FP 很自然的不会是 Statement。

当然在实务中不可能完全没有 I/O 的操作,Functional Programming 只要求对 I/O 操作限制到最小,不要有不必要的 I/O 行为,尽量保持运算过程的单纯。

Pure Function

Pure function 是指 一个 function 给予相同的参数,永远会回传相同的返回值,并且没有任何显著的副作用(Side Effect)

举个例子:

var arr = [1, 2, 3, 4, 5];

arr.slice(0, 3); // [1, 2, 3]

arr.slice(0, 3); // [1, 2, 3]

arr.slice(0, 3); // [1, 2, 3]

这裡可以看到 slice 不管执行几次,返回值都是相同的,并且除了返回一个值(value)之外并没有做任何事,所以 slice 就是一个 pure function。

var arr = [1, 2, 3, 4, 5];

arr.splice(0, 3); // [1, 2, 3]

arr.splice(0, 3); // [4, 5]

arr.slice(0, 3); // []

这裡我们换成用 splice,因为 splice 每执行一次就会影响 arr 的值,导致每次结果都不同,这就很明显不是一个 pure function。

Side Effect

Side Effect 是指一个 function 做了跟本身运算返回值没有关系的事,比如说修改某个全域变数,或是修改传入参数的值,甚至是执行 console.log 都算是 Side Effect。

Functional Programming 强调没有 Side Effect,也就是 function 要保持纯粹,只做运算并返回一个值,没有其他额外的行为。

这裡列举几个前端常见的 Side Effect,但不是全部

  • 发送 http request
  • 在画面印出值或是 log
  • 获得使用者 input
  • Query DOM 物件

Referential transparency

前面提到的 pure function 不管外部环境如何,只要参数相同,函式执行的返回结果必定相同。这种不依赖任何外部状态,只依赖于传入的参数的特性也称为 引用透明(Referential transparency)

利用参数保存状态

由于最近很红的 Redux 使我能很好的举例,让大家了解什麽是用参数保存状态。了解 Redux 的开发者应该会知 Redux 的状态是由各个 reducer 所组成的,而每个 reducer 的状态就是保存在参数中!

function countReducer(state = 0, action) {
// ...
}

如果你跟 Redux 不熟可以看下面递回的例子

function findIndex(arr, predicate, start = 0) {
    if (0 <= start && start < arr.length) {
        if (predicate(arr[start])) {
            return start;
        }
        return findIndex(arr, predicate, start+1);
    }
}
findIndex(['a', 'b'], x => x === 'b'); // 找阵列中 'b' 的 index

这裡我们写了一个 findIndex 用来找阵列中的元素位置,我们在 findIndex 中故意多塞了一个参数用来保存当前找到第几个 index 的状态,这就是利用参数保存状态!

这边用到了递回,递回会不断的呼叫自己,製造多层 stack frame,会导致运算速度较慢,而这通常需要靠编译器做优化!

那 JS 有没有做递回优化呢? 恭喜大家,ES6 提供了 尾呼优化(tail call optimization),让我们有一些手法可以让递回更有效率!

Functional Programming 优势

可读性高

当我们透过一系列的函式封装资料的操作过程,程式码能变得非常的简洁且可读性极高,例如下面的例子

[9, 4].concat([8, 7]) // 合併阵列
      .sort()  // 排序
      .filter(x => x > 5) // 过滤出大于 5 的

可维护性高

因为 Pure function 等特性,执行结果不依赖外部状态,且不会对外部环境有任何操作,使 Functional Programming 能更好的除错及撰写单元测试。

易于併行/平行处理

Functional Programming 易于做併行/平行(Concurrency/Parallel)处理,因为我们基本上只做运算不碰 I/O,再加上没有 Side Effect 的特性,所以较不用担心 deadlock 等问题。

今日小结

今天讲了 Functional Programming 的基本特性,及其优势。现在愈来愈多的 Library 用到了 FP 的观念,JS 也越来越多 Functional 的函式库,例如:Lodash, Underscore, lazy, Ramda。了解 FP 的基本观念有助于我们在学习其他 Library 更容易上手,也能使我们撰写出更好的程式码,希望各位读者有所收穫,若有任何疑问欢迎在下方留言给我

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容