函数柯里化定义:将一个多参数函数拆解成一串连续的链式函数,每个小函数接受单一参数Arity = 1
,并return另一个函数接受下一个参数。一种特殊的偏函数。
这种技巧,就叫Currying (柯里化)。
柯里化实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function curry(fn, argsLength = fn.length) { let args = []
return function curried(nextArgs) { args = [...args, nextArgs] if (args.length >= argsLength) { return fn(...args) } else { return curried } } }
function sum(x, y, z) { return x + y + z } const currySum = curry(sum) console.log(currySum(10)(10)(10))
|
这种实现有问题,就是调用了一次currySum(10)(10)(10)
之后,再次调用currySum(10)(10)(10)
会报错。因为在第二次再次调用的时候,由于args是「共享」的,args中已经是[10, 10, 10]
了。currySum(10)
会调用fn
返回结果,而不是返回函数自身curried
。
报错信息是: TypeError: currySum(...) is not a function
解决方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function curry (fn, ARITY = fn.length) { return (function nextCurried (prevArgs) { return function curried (nextArg) { var args = [...prevArgs, nextArg]
if (args.length >= ARITY) { return fn(...args) } else { return nextCurried(args) }
} })([]) }
|
对于不明确参数个数的函数,可以通过curry的第二个参数指定参数个数。例如:
1 2 3 4 5 6 7 8 9
| function sum(...args) { var sum = 0; for (let i = 0; i < args.length; i++) { sum += args[i]; } return sum; } var curriedSum = curry( sum, 5 ); curriedSum( 1 )( 2 )( 3 )( 4 )( 5 );
|
除此之外,还可以使用 lodash.js
的curry函数:
1 2 3 4 5 6 7 8
| var abc = function(a, b, c) { return [a, b, c]; }; var curried = lodash.curry(abc); curried(1)(2)(3);
curried(1, 2)(3);
|