compose函數(shù)
compose函數(shù)可以將需要嵌套執(zhí)行的函數(shù)平鋪骨稿,嵌套執(zhí)行就是一個(gè)函數(shù)的返回值將作為另一個(gè)函數(shù)的參數(shù)。我們考慮一個(gè)簡單的需求:
給定一個(gè)輸入值x崔拥,先給這個(gè)值加10贝乎,然后結(jié)果乘以10
這個(gè)需求很簡單柴淘,直接一個(gè)計(jì)算函數(shù)就行:
const calculate = x => (x + 10) * 10;
let res = calculate(10);
console.log(res); // 200
但是根據(jù)我們之前講的函數(shù)式編程关斜,我們可以將復(fù)雜的幾個(gè)步驟拆成幾個(gè)簡單的可復(fù)用的簡單步驟示括,于是我們拆出了一個(gè)加法函數(shù)和一個(gè)乘法函數(shù):
const add = x => x + 10;
const multiply = x => x * 10;
// 我們的計(jì)算改為兩個(gè)函數(shù)的嵌套計(jì)算铺浇,add函數(shù)的返回值作為multiply函數(shù)的參數(shù)
let res = multiply(add(10));
console.log(res); // 結(jié)果還是200
上面的計(jì)算方法就是函數(shù)的嵌套執(zhí)行痢畜,而我們compose
的作用就是將嵌套執(zhí)行的方法作為參數(shù)平鋪,嵌套執(zhí)行的時(shí)候鳍侣,里面的方法也就是右邊的方法最開始執(zhí)行丁稀,然后往左邊返回,我們的compose
方法也是從右邊的參數(shù)開始執(zhí)行倚聚,所以我們的目標(biāo)就很明確了线衫,我們需要一個(gè)像這樣的compose
方法:
// 參數(shù)從右往左執(zhí)行,所以multiply在前惑折,add在后
let res = compose(multiply, add)(10);
那這個(gè)compose方法要怎么實(shí)現(xiàn)呢授账,這里需要借助Array.prototype.reduce
,這個(gè)方法會(huì)從左往右迭代惨驶,但是我們需要的是從右往左迭代白热,這個(gè)方法是Array.prototype.reduceRight
:
const compose = function(){
// 將接收的參數(shù)存到一個(gè)數(shù)組, args == [multiply, add]
const args = [].slice.apply(arguments);
return function(x) {
return args.reduceRight((res, cb) => cb(res), x);
}
}
// 我們來驗(yàn)證下這個(gè)方法
let calculate = compose(multiply, add);
let res = calculate(10);
console.log(res); // 結(jié)果還是200
上面的compose
函數(shù)使用ES6的話會(huì)更加簡潔:
const compose = (...args) => x => args.reduceRight((res, cb) => cb(res), x);
Redux的中間件就是用compose
實(shí)現(xiàn)的粗卜,webpack中l(wèi)oader的加載順序也是從右往左屋确,這是因?yàn)樗彩?code>compose實(shí)現(xiàn)的。
pipe函數(shù)
pipe
函數(shù)跟compose
函數(shù)的左右是一樣的续扔,也是將參數(shù)平鋪攻臀,只不過他的順序是從左往右。我們來實(shí)現(xiàn)下纱昧,只需要將reduceRight
改成reduce
就行了:
const pipe = function(){
const args = [].slice.apply(arguments);
return function(x) {
return args.reduce((res, cb) => cb(res), x);
}
}
// 參數(shù)順序改為從左往右
let calculate = pipe(add, multiply);
let res = calculate(10);
console.log(res); // 結(jié)果還是200
ES6寫法:
const pipe = (...args) => x => args.reduce((res, cb) => cb(res), x)