柯里化
什麼是柯里化(Currying)
柯里化是 functional programming 的一項技術,它可以將擁有多個引數的函式轉換成函式序列。
function sum(a, b) {
return a + b;
}
const curriedSum = curry(sum);
curriedSum(1)(2); // 3
curriedSum(1, 2); // 3
curriedSum()(1)(2); // 3
實際應用
1. 可重複使用的功能函式
const add = (a) => (b) => a + b;
const add1 = add(1);
console.log(add1(2)); // 3
console.log(add1(3)); // 5
2. 事件處理
const button = document.getElementById('button');
const handleButtonClick = (id) => (event) => console.log(`Button Id: ${id}, ${event}`);
button.addEventListener('click', handleButtonClick(3));
3. 客製化 API
const apiCall = (baseUrl) => (endPoint) => fetch(`${baseUrl}${endPoint}`);
const jsonPlaceholderApi = apiCall('https://jsonplaceholder.typicode.com');
const getUsers = jsonPlaceholderApi('/users');
4. 函式組合
const compose = (f, g) => (x) => f(g(x));
const double = (x) => x * 2;
const square = (x) => x * x;
const doubleThenSquare = compose(square, double);
console.log(doubleThenSquare(3)); // 36
實作 I
給定一個函式 fn
,回傳該函式的柯里化版本。
const fn = (a, b) => a + b;
const curriedFn = curry(fn);
curriedFn(1)(2); // 3
curriedFn(1, 2); // 3
curriedFn()(1)(2); // 3
思路
curry
函式將會回傳一個新的函式curried
,該函式接收任意數量的參數。- 檢查
curried
的參數數量是否大於或等於fn
函式的參數數量。 - 如果是,那麼呼叫
fn
函式並將curried
的參數傳遞給它。 - 如果不是,那麼回傳一個新的函式,該函式接收其他參數,並將
curried
的參數與它們傳入curried
函式。 - 遞迴呼叫
curried
函式,直到curried
函式的參數數量大於或等於fn
函式的參數數量,然後回傳最終的結果。
function curry(fn) {
// curry 函式將會回傳一個新的函式 curried,該函式接收任意數量的參數
return function curried(...args) {
// 檢查 curried 的參數數量是否大於或等於 fn 函式的參數數量
if (args.length >= fn.length) {
// 如果是,那麼呼叫 fn 函式並將 curried 的參數傳遞給它
return fn.apply(this, args);
}
// 如果不是,那麼回傳一個新的函式,該函式接收其他參數,並將 curried 的參數與它們傳入 curried 函式
return function (...otherArgs) {
// 遞迴呼叫 curried 函式,直到 curried 函式的參數數量大於或等於 fn 函式的參數數量
return curried(...args, ...otherArgs);
};
};
}
實作 II
給定一個函式 fn
,回傳該函式的柯里化版本。
const sum = (...args) => args.reduce((acc, val) => acc + val, 0);
const curriedSum = curry(sum);
console.log(curriedSum()); // 0
console.log(curriedSum(1)()); // 1
console.log(curriedSum(1)(2)()); // 3
function curry(fn) {
return function curried(...args) {
if (args.length === 0) {
return fn.apply(this);
}
return (...otherArgs) => {
if (otherArgs.length === 0) {
return fn.apply(this, args);
}
return curried.apply(this, [...args, ...otherArgs]);
};
};
}
實作 III
console.log(add(5)()); // 5
console.log(add(5)(3)); // fn
console.log(add(5)(3)()); // 8
function add(a) {
return (b) => {
if (b === undefined) {
return a;
}
return add(a + b);
};
}
參考來源: