函数柯里化

98 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

听到函数柯里化这个概念是在好几年前了,有去了解过,但一直是很模糊的印象,如果在面试过程中问到还真难以说清楚,所以决定再去好好研究下。做好笔记。

柯里化到底是什么?

柯里化(Currying):把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 -- 别人

怎么理解这句话呢?请看下面例子:

    // 假设现在有个函数有4个参数, 期望是返回传入参数的累加值
    funtion add(a, b, c, d){
        return a + b + c + d
    }
    add(1, 2, 3, 4)  // 10
    
    // 那么所谓的柯里化(换成颗粒化可能更容易理解)就是把传入多个参数的函数改造成每次只传入一个参数,分多次调用实现原函数功能的方法
    function curryAdd(w){
        return function(x){
            return function(y){
                return function(z){
                    return w + x + y + z
                }
            }
        }
    }
    curryAdd(1)(2)(3)(4) // 10
    // curryAdd(1)(2)(3)(4)其实拆分开来更好理解,前三次每次都反回了一个新的函数,等价于
    addA = curryAdd(1)
    addB = addA(2)
    addC = addB(3)
    addC(4) // 10 最后一个参数才是返回结果,前面的都是返回了一个函数并利用闭包的特性保存的传入的参数
    
    // 😓看起来更复杂了,但是在一些复用性比较高的函数中可以少写很多代码

上面的例子只能处理4个参数的情况,那如果多一些参数或少一些参数呢?每次要重新写一个柯里化函数?能不能处理参数个数不确定的情况?

答案是:可以的,用一个经典面试题来说明吧

面试题:实现一个函数,同时满足add(1),add(1)(2),add(1)(2)(3),...add(1)...(n)的求值

    function add() {
        let args = [...arguments]
        let calcFn = function() {
            args = [...args, ...arguments]
            let count =  args.reduce((a, b) => {
                    return a + b;
            },0)
            return arguments.length == 0 ? count : calcFn;
        };
        return calcFn;
    }
    add(1)(3)() // 4
    add(1)(2)(3)() // 6