看到柯里化(Currying),我相信爱好篮球的程序员一定会想到斯蒂芬·库里(Stephen Curry),常常投出不讲理的三分,让对手和队友目瞪口呆。函数柯里化也要讲究"得分效率"哦,在使用它时,应该考虑可读性与维护性,不要一不小心多炫啦。
函数柯里化
一、概念
定义: 它是将多参数函数转化为一系列单参数函数的技术,以逻辑学家Haskell Curry名字命名。
核心思想:将一个接受多个参数的函数转化为一系列链式函数调用,每个函数接受原函数的一个参数,并返回一个新的函数,直到所有参数都被接收为止。
二、为什么能实现?
一等公民的函数: 在JavaScript中,函数可以像变量一样被赋值给变量,作为参数传递给其他函数,或者从函数中返回。这是实现柯里化的基础。
闭包: 闭包允许一个函数访问并操作其外部作用域中的变量。在柯里化中,每次返回的新函数都会形成一个闭包,保持对外部函数中变量的引用,以便在后续调用中继续使用。
不定参数列表: 在箭头函数中使用 ...args
可以捕获所有传入的参数作为一个数组,这使得函数可以接受任意数量的参数,非常适用于实现柯里化求和这样的功能。
三、arguments与rest参数
arguments:
- 函数运行时参数管理对象 --> 类数组对象
- Object.prototype.toString.call(arguments) ==
[object Arguments]
- 具有
for .length
的能力,但是forEach,join reduce
等方法是没有的。
javascript
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4),Object.prototype.toString.call(arguments));
rest参数
- 从ES6开始,JavaScript引入了
rest
参数语法,它允许你在一个函数中收集不定数量的参数到一个数组中。 rest
参数必须是函数参数列表中的最后一个参数。
现代JavaScript倾向于使用rest参数而不是 arguments
,因为它提供了更好的语义清晰度和更丰富的数组操作能力。
javascript
function sum(...numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4)); // 输出:10
四、柯里化
add()
函数实现一个简单的函数柯里化
javascript
function add(x) {
return function(y) {
return x + y;
};
}
const add5 = add(5);
console.log(add5(3)); // 输出 8
在add(5)
的执行结果返回新函数add5
后,add5在接受参数3,add5(3)
的执行结果输出8。
在实际的应用中,它可以用于创建更加灵活和可重用的函数。例如,在一个需要多个参数的复杂函数中,可能在不同情况下只要设置某些参数,而其他的参数保持未确定的状态。通过柯里化,你可以创建一个函数家族,每个函数都针对特定场景进行了优化。
- 更复杂的函数柯里化----接受任意参数并求和。
ini
const curryAdd = (...args) => {
let total = args.reduce((acc, val) => acc + val, 0);
const foo = (...moreArgs) => {
if (moreArgs.length > 0) {
return curryAdd(...args, ...moreArgs);
} else {
return total;
}
};
return foo;
};
const curriedAdd = curryAdd();
console.log(curriedAdd(1,2)(2,2)(3,4)(4,6)());
在这个更加复杂的柯里化中,curryAdd
函数可以接受任意数量参数,计算合后返回内部函数foo
,当foo
被调用时,接受到更多的参数,它会递归调用curryAdd
并将新的参数与已有参数合并,没有更多参数时,返回total。
注: reduce
方法接受一个回调函数作为参数,这个函数接受两个参数,一个当前值,一个当前数组元素,这个回调函数会在数组的每个元素上调用一次。在接受一个初始值,这里为0。