30 天精通 RxJS (02): Functional Progra
什麼是 Functional Programming ?
Functional Programming 是一種程式設計正規化(programming paradigm),就像 Object-oriented Programming(OOP)一樣,就是一種寫程式的方法論,這些方法論告訴我們如何思考及解決問題。
簡單說 Functional Programming 核心思想就是做運算處理,並用 function 來思考問題,例如像以下的算數運算式:
(5 + 6) - 1 * 3
我們可以寫成
const add = (a, b) => a + bconst mul = (a, b) => a * bconst 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('') .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;
有時候表示式也可能同時是合法的陳述式,這裡只講基本的判斷方法。如果想更深入瞭解其中的差異,可以看這篇文章
由於 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 x === 'b'); // 找陣列中 'b' 的 index
這裡我們寫了一個 findIndex 用來找陣列中的元素位置,我們在 findIndex
中故意多塞了一個引數用來儲存當前找到第幾個 index 的狀態,這就是利用引數儲存狀態!
這邊用到了遞迴,遞迴會不斷的呼叫自己,製造多層 stack frame,會導致運算速度較慢,而這通常需要靠編譯器做最佳化!
那 JS 有沒有做遞迴最佳化呢? 恭喜大家,ES6 提供了 ,讓我們有一些手法可以讓遞迴更有效率!
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 更容易上手,也能使我們撰寫出更好的程式碼,希望各位讀者有所收穫,若有任何疑問歡迎在下方留言給我
作者:readilen
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4328/viewspace-2814306/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 30 天精通 RxJS (01):認識 RxJSJS
- 30 天精通 RxJS (21):深入 ObservableJS
- 30 天精通 RxJS (05): 建立 Observable(一)JS
- 30 天精通 RxJS (25):Subject 總結JS
- 30 天精通 RxJS (12):Observable Operator - scan, bufferJS
- 30 天精通 RxJS (15):Observable Operators - distinct, distinctUntilChangedJS
- 30 天精通 RxJS(23): Subject, BehaviorSubject, ReplaySubject, AsyncSubjectJS
- 30 天精通 RxJS (23):Subject, BehaviorSubject, ReplaySubject, AsyncSubjectJS
- 30 天精通 RxJS (26):簡易實作 Observable(一)JS
- 30 天精通 RxJS (16):Observable Operators - catch, retry, retryWhen, repeatJS
- 30 天精通 RxJS(20): Observable Operators - window, windowToggle, groupByJS
- 30 天精通 RxJS (17):Observable Operators - switch, mergeAll, concatAllJS
- 30 天精通 RxJS (09):Observable Operator - skip, takeLast, last, concat, startWith, mergeJSAST
- RxJS 系列之一 – Functional Programming 簡介JSFunction
- RxJS 系列之一 - Functional Programming 簡介JSFunction
- 30分鐘精通React HooksReactHook
- E - Reachability in Functional GraphFunction
- [轉]Golang Functional Options PatternGolangFunction
- Rxjs 01-認識RxjsJS
- 30天學RxSwift——ObserverSwiftServer
- 100天精通Python—第34天:正規表示式大總結Python
- RxJSJS
- 30天自制作業系統:第三天作業系統
- [RxJS] Introduction to RxJS Marble TestingJS
- RxJS實踐,Vue如何整合RxJSJSVue
- Python 從入門到精通:30天速成教程到底有多狠?你能堅持下來嗎?Python
- 30天學習編寫30個Swift小程式Swift
- 混合OO和Functional設計Function
- 機器學習30天進階實戰機器學習
- RxJS的學習之路一(RxJS初探)JS
- RxJS -- SubscriptionJS
- RXJS 概述JS
- ZG前端學習第二天2020-10-30前端
- rxjs入門4之rxjs模式設計JS模式
- 開始學習Functional ProgrammingFunction
- 巧用 Rational Functional Tester 的 IWindow 介面Function
- 2022世界人工智慧大會倒數計時30天人工智慧
- 20160220.CCPP體系詳解(0030天)