JavaScript 函數語言程式設計中 compose 實現
上一篇文章介紹了javascript
函數語言程式設計中curry
(柯里化)的實現,當然那個柯里化是有限引數的柯里化,等有機會在補上無限引數的那一種柯里化,這次主要說的是javascript
函數語言程式設計中另外一個很重要的函式compose
,compose
函式的作用就是組合函式的,將函式串聯起來執行,將多個函式組合起來,一個函式的輸出結果是另一個函式的輸入引數,一旦第一個函式開始執行,就會像多米諾骨牌一樣推導執行了。
簡介
比如有這樣的需求,要輸入一個名字,這個名字有由firstName
,lastName
組合而成,然後把這個名字全部變成大寫輸出來,比如輸入jack
,smith
我們就要列印出來,‘HELLO,JACK SMITH’
。
我們考慮用函式組合的方法來解決這個問題,需要兩個函式greeting
, toUpper
var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastName var toUpper = str => str.toUpperCase() var fn = compose(toUpper, greeting) console.log(fn('jack', 'smith')) // ‘HELLO,JACK SMITH’
這就是compose大致的使用,總結下來要注意的有以下幾點
compose
的引數是函式,返回的也是一個函式- 因為除了第一個函式的接受引數,其他函式的接受引數都是上一個函式的返回值,所以初始函式的引數是
多元
的,而其他函式的接受值是一元
的 compsoe
函式可以接受任意的引數,所有的引數都是函式,且執行方向是自右向左
的,初始函式一定放到引數的最右面
知道這三點後,就很容易的分析出上個例子的執行過程了,執行fn('jack', 'smith')
的時候,初始函式為greeting
,執行結果作為引數傳遞給toUpper
,再執行toUpper
,得出最後的結果,compose的好處我簡單提一下,如果還想再加一個處理函式,不需要修改fn
,只需要在執行一個compose
,比如我們再想加一個trim
,只需要這樣做
var trim = str => str.trim() var newFn = compose(trim, fn) console.log(newFn('jack', 'smith'))
就可以了,可以看出不論維護和擴充套件都十分的方便。
實現
例子分析完了,本著究其根本的原則,還是要探究與一下compose
到底是如何實現的,首先解釋介紹一下我是如何實現的,然後再探求一下,javascript
函數語言程式設計的兩大類庫,lodash.js
和ramda.js
是如何實現的,其中ramda.js
實現的過程非常函式式。
我的實現
我的思路是,既然函式像多米諾骨牌式的執行,我首先就想到了遞迴,下面就一步一步的實現這個compose
,首先,compose
返回一個函式,為了記錄遞迴的執行情況,還要記錄引數的長度len
,還要給返回的函式新增一個名字f1
。
var compose = function(...args) { var len = args.length return function f1() { } }
函式體裡面要做的事情就是不斷的執行args
中的函式,將上一個函式的執行結果作為下一個執行函式的輸入引數,需要一個遊標count
來記錄args
函式列表的執行情況。
var compose = function(...args) { var len = args.length var count = len - 1 var result return function f1(...args1) { result = args[count].apply(this, args1) count-- return f1.call(null, result) } }
這個就是思路,當然這樣是不行的,沒有退出條件,遞迴的退出條件就是最後一個函式執行完的時候,也就是count
為0
的時候,這時候,有一點要注意,遞迴退出的時候,count
遊標一定要回歸初始狀態,最後補充一下程式碼
var compose = function(...args) { var len = args.length var count = len - 1 var result return function f1(...args1) { result = args[count].apply(this, args1) if (count <= 0) { count = len - 1 return result } else { count-- return f1.call(null, result) } } }
這樣就實現了這個compose
函式。後來我發現遞迴這個完全可以使用迭代來實現,使用while
函式看起來更容易明白,其實lodash.js
就是這麼實現的。
lodash
實現
lodash
的思路同上,不過是用迭代實現的,我就把它的原始碼貼過來看一下
var flow = function(funcs) { var length = funcs.length var index = length while (index--) { if (typeof funcs[index] !== 'function') { throw new TypeError('Expected a function'); } } return function(...args) { var index = 0 var result = length ? funcs[index].apply(this, args) : args[0] while (++index < length) { result = funcs[index].call(this, result) } return result } } var flowRight = function(funcs) { return flow(funcs.reverse()) }
可以看出,lodash
的本來實現是從左到右
的,但也提供了從右到左
的flowRight
,還多了一層函式的校驗,而且接收的是陣列
,不是引數序列
,而且從這行var result = length ? funcs[index].apply(this, args) : args[0]
可以看出允許陣列為空,可以看出還是非常嚴謹的。我寫的就缺少這種嚴謹的異常處理。
結論
這次主要介紹了函數語言程式設計中的compose
函式的原理和實現方法,由於篇幅原因,我把打算分析的ramda.js
原始碼實現放到下一篇來介紹,可以說ramda.js
實現的compose
更加函式式,需要單獨好好分析。
相關文章
- JavaScript 函數語言程式設計中的 curry 實現JavaScript函數程式設計
- 使用JavaScript實現“真·函數語言程式設計”JavaScript函數程式設計
- 函數語言程式設計之Compose函數程式設計
- JavaScript中的函數語言程式設計JavaScript函數程式設計
- JavaScript 中的函數語言程式設計JavaScript函數程式設計
- 使用JavaScript實現“真·函數語言程式設計”-2JavaScript函數程式設計
- javascript函數語言程式設計JavaScript函數程式設計
- JavaScript 函數語言程式設計JavaScript函數程式設計
- 函數語言程式設計入門實踐 —— Compose/Pipe函數程式設計
- JavaScript 函數語言程式設計(二)JavaScript函數程式設計
- JavaScript 函數語言程式設計(一)JavaScript函數程式設計
- JavaScript 函數語言程式設計(三)JavaScript函數程式設計
- JavaScript函數語言程式設計(二)JavaScript函數程式設計
- JavaScript函數語言程式設計(一)JavaScript函數程式設計
- JavaScript函數語言程式設計(三)JavaScript函數程式設計
- 【譯】JavaScript 中的函數語言程式設計原理JavaScript函數程式設計
- DDD的函數語言程式設計實現函數程式設計
- [譯] JavaScript 函數語言程式設計指引JavaScript函數程式設計
- 『翻譯』JavaScript 函數語言程式設計JavaScript函數程式設計
- JavaScript函數語言程式設計學習JavaScript函數程式設計
- JavaScript 函數語言程式設計介紹JavaScript函數程式設計
- JavaScript 函數語言程式設計導論JavaScript函數程式設計
- JavaScript函數語言程式設計之副作用JavaScript函數程式設計
- JavaScript 函數語言程式設計---柯里化JavaScript函數程式設計
- 深入學習javascript函數語言程式設計JavaScript函數程式設計
- 我眼中的 JavaScript 函數語言程式設計JavaScript函數程式設計
- JavaScript學習(3):函數語言程式設計JavaScript函數程式設計
- 函數語言程式設計 - 實現響應式框架函數程式設計框架
- 函數語言程式設計函數程式設計
- 函數語言程式設計最佳實踐函數程式設計
- Scala 函數語言程式設計(一) 什麼是函數語言程式設計?函數程式設計
- JavaScript函數語言程式設計入門經典JavaScript函數程式設計
- JavaScript函數語言程式設計無痛入門JavaScript函數程式設計
- JavaScript函數語言程式設計(1):基本思想JavaScript函數程式設計
- javascript函數語言程式設計簡單介紹JavaScript函數程式設計
- javascript函數語言程式設計 : call 和 applyJavaScript函數程式設計APP
- 使用 JavaScript 進行函數語言程式設計 (一)JavaScript函數程式設計
- 瞭解 JavaScript 函數語言程式設計 - 宣告式函式JavaScript函數程式設計函式