适用于任何场景的函数柯里化

244 阅读2分钟

为什么要使用柯里化?

在实际开发中,可能会遇到需要固定某个函数的值,接着后面的若干个参数,需要依赖前面的某个函数返回值。

多说无益,直接放码

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参数是有顺序的,如果写反顺序就反了,比如

image.png

优化代码,提高适用性

这就足够了吗?

不,还是不够方便,要是我初始化就要传入参数呢?比如这样

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));
        };
    };
}

image.png

只需要在判断里面,加入初始化的参数判断,并将拼接上即可

乂,这不就解决了吗,随便你怎么写都行