Currying是甚麼
鴉片不是鴨子的切片,Currying也是不是咖哩,其名稱源於其發明者Haskell Curry
它是一種functional programming
(函式程式設計)的概念。會將一個接受多個參數
的函式拆成多個只接受一個參數的函式
,概念和partial類似,差別在partial可以接受複數個參數
使用
Currying很適合
用在傳遞相同的參數給同個函式時
,因為它利用閉包記憶函式建立時的環境的特性
來讓程式碼更簡潔
未Curried
const isMoneyEnough = (passiveRes, negativeRes, budget, price) => {
return budget >= price ? passiveRes : negativeRes;
};
isMoneyEnough('enough', 'not enough', 200, 105);
isMoneyEnough('enough', 'not enough', 200, 1000);
isMoneyEnough('enough', 'not enough', 200, 200);
Curried後
const isMoneyEnough = (passiveRes, negativeRes) => {
return (price) => {
return (budget) => {
return budget >= price? passiveRes : negativeRes;
}
}
}
// 也可簡化成這樣
// const isMoneyEnough = (passiveRes, negativeRes) => price => budget => budget >= price ? passiveRes : negativeRes;
const isMoneyEnough = isMoneyEnough('enough', 'not enough')(200);
isMoneyEnough(105);
isMoneyEnough(1000);
isMoneyEnough(200);
進階使用
function curry(func) {
return function curried(...args) {
// 如果傳入的參數數量不小於傳入的函式接收的參數長度
if (args.length >= func.length) {
// 使用apply讓curried能用傳進來的函式的功能
return func.apply(this, args);
} else {
return function(...args2) {
// 使用apply讓這個函式能用curried的功能
// 這樣是因為參數的數量小於傳入函式接收的參數長度時
// 如果直接func.apply(this, args)會報錯
// 所以才用類似遞迴的方式
// 一次一次把參數連接起來到長度足夠才會進入if並執行
return curried.apply(this, args.concat(args2));
}
}
};
}
function sum(a, b, c) {
return a + b + c;
}
let curriedSum = curry(sum);
curriedSum(1, 2, 3); // 直接進去if
curriedSum(1, 2)(3); // 先進去else,此時args為[1, 2]。傳3進去後concat得到[1, 2, 3],進去if
curriedSum(1)(2)(3); // 先進去else,此時args為[1]。傳2進去concat得到[1, 2],再進去else。傳3進去後concat得到[1, 2, 3],進去if
currying優點
將程式碼
依功能拆解
成更小單元,有助於重複利用
- 利用
閉包特性
來讓程式碼更簡潔
,達到DRY - 函式參數越多處理時會更加複雜。而curried function
一次
只處理一個參數
,提高
程式的彈性、可讀性