JavaScript 函数柯里化
什么是函数柯里化?
函数柯里 化(Currying)是一种函数式编程技术,它是以数学家哈斯凯尔·柯里(Haskell Curry)命名的。简单来说,柯里化是将一个接受多个参数的函数转换为一系列使用一个参数的函数的过程。
备注
柯里化不会调用函数,它只是对函数进行转换。
在JavaScript中,柯里化后的函数不再一次接收所有参数,而是返回一个新函数,这个新函数接收下一个参数,依此类推,直至收到所有参数后,返回最终结果。
函数柯里化的基本形式
假设有一个函数 add
,接收三个参数并返回它们的和:
// 普通函数
function add(a, b, c) {
return a + b + c;
}
console.log(add(1, 2, 3)); // 输出: 6
柯里化后的版本如下:
// 柯里化后的函数
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(curriedAdd(1)(2)(3)); // 输出: 6
每调用一次,都会返回一个新函数,直到最后一个参数被传入,才会计算并返回最终结果。
ES6箭头函数简化柯里化
使用ES6的箭头函数可以使柯里化函数 的代码更加简洁:
const curriedAdd = a => b => c => a + b + c;
console.log(curriedAdd(1)(2)(3)); // 输出: 6
创建通用的柯里化函数
我们可以编写一个通用的柯里化函数,它接收一个函数并返回这个函数的柯里化版本:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}
// 使用通用柯里化函数
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 输出: 6
console.log(curriedAdd(1, 2)(3)); // 输出: 6
console.log(curriedAdd(1)(2, 3)); // 输出: 6
console.log(curriedAdd(1, 2, 3)); // 输出: 6
这个通用柯里化函数允许我们以多种方式传递参数,只要最终传递的参数数量等于原始函数所需的参数数量即可。
函数柯里化的优点
1. 参数复用
柯里化允许我们固定某些参数,创建一个新的函数,这对于代码复用非常有用:
function discount(discount) {
return function(price) {
return price * (1 - discount);
};
}
const tenPercentDiscount = discount(0.1);
const twentyPercentDiscount = discount(0.2);
console.log(tenPercentDiscount(100)); // 输出: 90
console.log(twentyPercentDiscount(100)); // 输出: 80
2. 延迟执行
柯里化可以帮助我们延迟函数的执行,直到收集到所有需要的数据:
const loggerHelper = format => date => message => {
console.log(`[${format(date)}] ${message}`);
};
const timeFormat = date => `${date.getHours()}:${date.getMinutes()}`;
const simpleFormat = date => `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`;
const timeLogger = loggerHelper(timeFormat);
const todayLogger = timeLogger(new Date());
todayLogger("Function currying is awesome!");
// 输出格式例如: [14:25] Function currying is awesome!
3. 提高可读性
对于一些特定类型的代码,柯里化可以使代码更加可读和组合性更强:
// 未柯里化的过滤函数
function filter(arr, predicate) {
return arr.filter(predicate);
}
// 柯里化版本
const curriedFilter = predicate => arr => arr.filter(predicate);
const isEven = x => x % 2 === 0;
const getEvenNumbers = curriedFilter(isEven);
console.log(getEvenNumbers([1, 2, 3, 4, 5, 6])); // 输出: [2, 4, 6]