函數式編程中有一種模式是通過組合多個函數的功能來實現一個組合函數。一般支持函數式編程的工具庫都實現了這種模式,這種模式一般被稱作compose與pipe。以函數式著稱的Ramda工具庫為例。
const R = require('ramda');
function inc (num) {
return ++num;
}
const fun1 = R.compose(Math.abs, inc, Math.pow)
const fun2 = R.pipe(Math.pow, Math.abs, inc)
console.log(fun1(-2, 3)) // 7
console.log(fun2(-2, 3)) // 9
從上面的例子可以看出,假設f
、g
、h
分別表示三個函數,則compose(f,g,h)
返回的函數完成類似(...args) => f(g(h(...args)))
的功能。即從右到左組合多個函數,前面函數的返回值作為下一個函數的參數;pipe(f,g,h)
返回的函數完成類似(...args) => h(g(f(...args)))
的功能,即從左到右組合多個函數,前面函數的返回值作為下一個函數的參數;預計最先執行的函數可以接受任意個參數,后面的函數預計只接受一個參數。把compose
放在前面講是因為其更加體現了數學含義上的從右到左的操作。
redux
中即有使compose
函數的應用來增強store
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import DevTools from './containers/DevTools'
import reducer from '../reducers'
const store = createStore(
reducer,
compose(
applyMiddleware(thunk),
DevTools.instrument()
)
)
總的來說,compose
和pipe
函數接收函數序列,並返回一個函數,使用數組的reduce
方法可以很容易實現這兩個函數,下面是redux
源碼中對compose
方法的實現:
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
上面的代碼是ES6+的實現方式,仿照上面的代碼很容易寫出ES5的實現方法
function _compose(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
};
}
function compose() {
var args = Array.prototype.slice.call(arguments)
if (args.length === 0) {
return function(arg){
return arg
}
}
if (args.length === 1) {
return args[0]
}
return args.reduce(_compose)
}
實現了compose
方法,只需要改動很少的地方就能實現pipe
方法。
function pipe(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => b(a(...args)))
}
或者直接借助compose
方法實現pipe
function pipe(...funcs){
if(funcs.length === 0) {
return arg => arg
}
return compose(...funcs.reverse())
}
組合的概念來自於數學,其有一個重要的特性就是結合律
// 結合律(associativity)
var associative = compose(f, compose(g, h)) == compose(compose(f , g), h); // true
符合結合律意味着不管你是把g
和 h
分到一組,還是把f
和g
分到一組都不重要。在實際開發過程中,我們可以盡可能的最小化函數的功能,這也符合單一原則,然后通過結合以及組合來完成較大的功能需求。