为什么要使用柯里化?
在实际开发中,可能会遇到需要固定某个函数的值,接着后面的若干个参数,需要依赖前面的某个函数返回值。
多说无益,直接放码
function fn(p1) {
return (...args) => {
return p1 + args.reduce((init, item) => init + item, 0)
}
}
const fixedFn = fn(1);
const p1 = fixedFn(10),
p2 = fixedFn(20, 30),
p3 = fixedFn(30, 40, 50);
console.log(p1) // 11
console.log(p2) // 51
console.log(p3) // 121
这里p1 p2 p2都依赖的fixedFn的返回值,继续计算。
这样看着还行,但是不够优雅,于是...
function curry() {
// 取出函数,以及后续参数
const fn = Array.prototype.slice.call(arguments, 0, 1)[0],
rest = Array.prototype.slice.call(arguments, 1);
// 后续参数数量 >= 函数形参数量 直接返回
if (rest.length >= fn.length) {
return fn.apply(this, rest)
}
// 返回新的函数 利用闭包收集参数
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args)
}
return function (...moreArgs) {
return curried.apply(this, args.concat(moreArgs))
}
}
}
function sum(a, b, c) {
console.log(a)
console.log(b)
console.log(c)
// return a + b + c
}
const fn = curry(sum);
const fixedFn = fn(1, 2)
fixedFn(3) // 1 2 3
如果curry函数接收的参数不够,那就返回一个新函数,继续接收剩余参数,
等到参数够了,就返回结果,这样就完成了
注意!!
concat参数是有顺序的,如果写反顺序就反了,比如
优化代码,提高适用性
这就足够了吗?
不,还是不够方便,要是我初始化就要传入参数呢?比如这样
function sum(a, b, c, d) {
console.log(a, b, c, d);
}
const fn = curry(sum, 1);
const fixedFn = fn(2)
fixedFn(3)(4)
初始化
fn时就固定了一些参数,那么阁下该如何应对呢?
function curry() {
const fn = Array.prototype.slice.call(arguments, 0, 1)[0],
rest = Array.prototype.slice.call(arguments, 1);
if (rest.length >= fn.length) {
return fn.call(this, ...rest);
}
return function curried(...args) {
// 只需要把开头参数数量拼接即可
if (args.length + rest.length >= fn.length) {
return fn.apply(this, rest.concat(args));
}
return function (...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
};
}
只需要在判断里面,加入初始化的参数判断,并将拼接上即可
乂,这不就解决了吗,随便你怎么写都行