目錄
pipe function
pipe function是接收一個或多個function,也是higher-order function的一種
它會由左而右
將function組合起來,其中最左邊的function可以接收任意數量的參數
一但最左側的function回傳了值
,其右邊
的function會接收
這個回傳值,並進行一些計算後再回傳另一個值
,直到所有
function都跑過
type CalculateFunction = (originalNumber:number, operatedNumber?:number) => number;
const pipe = (...fns: CalculateFunction[]) => {
return (...nums: number[]) => {
return fns.reduce((res, currFn, index) => {
// console.log(res, nums[index]);
return currFn(res, nums[index]);
}, 0);
}
}
const add = (a:number, b:number = 0) => a + b;
const divide = (a:number, b:number = 0) => a - b;
const multiply = (a:number, b:number = 1) => a * b;
const halfOff = (a:number) => a / 2;
const square = (a:number) => Math.pow(a, 2);
const getSquareRoot = (a: number) => Math.sqrt(a);
console.log(pipe(add, add, add, add)(1,2,3,4)); // 1+2+3+4
console.log(pipe(add, add, multiply, divide)(1,2,3,4)); // // (1+2)*3-4
compose function
compose function大致上和pipe function一樣,只差在順序是右而左
const compose = (...fns: CalculateFunction[]) => {
return (...nums:number[]) => {
return fns.reduceRight((res, currFn, index) => {
// console.log(res, nums[index]);
return currFn(res, nums[index]);
}, 0);
}
}
用起來會像這樣
console.log(compose(1, 2, 3, 4)); // 4+3+2+1
console.log(compose(add, add, multiply, divide)(1,2,3,4)); // ((0-4)*3)+1+2
為什麼要用pipe/compose function
如果不用pipe/compose
的話,當要進行一連串的處理時,就會得到一段非常巢狀的可讀性低
的code,且可讀性會隨著function數量增加而持續下降
// 相當於compose(1, 2, 3, 4)
console.log(add(add(add(1,2),3),4));
// 相當於pipe(add, add, multiply, divide)(1,2,3,4)
console.log(divide(multiply(add(1,2), 3),4));
value wrapper
value wrapper就是function chain,顧名思義就是用.把function連在一起,變得像是chain
在jQuery或者d3之類的library都會看到這個做法
const pipe = (value) => ({
value,
to: cb => pipe(cb(value))
})
const pipe = <T extends number | string>(value:T) => ({
value,
to: (cb:(d:T) => T) => pipe(cb(value))
})
console.log(
pipe<number>(1)
.to((n) => add(n, 2))
.to((n) => add(n, 3))
.to((n) => add(n, 4))
.value
);
console.log(
pipe<number>(1)
.to((n) => add(n, 2))
.to((n) => multiply(n, 3))
.to((n) => divide(n, 4))
.value
);
// 修改成currying function
const add = (a:number) => (b:number) => b + a;
const divide = (a:number) => (b:number = 0) => b - a;
const multiply = (a:number) => (b:number) => b * a;
const halfOff = (a:number) => a / 2;
const pipe = <T extends number | string>(value:T) => ({
value,
to: (cb:(d:T) => T) => pipe(cb(value))
})
console.log(
pipe<number>(1)
.to(add(2))
.to(add(3))
.to(add(4))
.value
);
console.log(
pipe<number>(1)
.to(add(2))
.to(multiply(3))
.to(divide(4))
.value
);
參考資料
Higher-Order Functions(HoF) in JavaScript - Explain Like I'm Five
Compose and Pipe in JavaScript
A quick introduction to pipe() and compose() in JavaScript
Function Piping in JavaScript