ranhao算法笔记(1)《函数柯里化》

304 阅读2分钟
  • 第一道菜

实现: 
    console.log(sum(1)(2)(3)) // 6
    console.log(sum(1)(5)) // 6
    console.log(sum(1)(2)(3)(4)) // 10

其实思想非常之简单

  1. 我们需要找办法收集好所有参数
  2. 收集完成后,触发某个事情把所有参数相加
function sum() {
    let arg = [...arguments]; // 开始收集第一个圆括号内的参数,放到arg中
    
    const fn = function() { // 收集函数
        arg.push(...arguments)
        return fn
    }
    fn.toString = function() { // 重写toString函数
        let result = arg.reduce((acc, val) => {
            return acc + val;
        }, 0)
        return result
    }
    return fn
}

我们举个例子 首先sum(1)(2)(3)

  1. 进去以后先执行的是sum(1),arg现在是[1],然后会return fn函数 也就是把收集函数返回了,这个收集函数的tostring方法被改写了。 arg.push(...arguments),
  2. 此时是变成了fn(2)(3),我们可以看看fn的函数定义,发现他可以处理2这个参数,现在执行arg.push(...arguments),arg变成了[1, 2]了,并且将自己导了出去。
  3. 接着fn(3),还是像上面那步一样,导入参数变成了(1, 2, 3)了,并且fn导了出去。此时console出现,执行fn的tostring方法,返回result。

影流之主的分割线。。。。。。。。。。。。。。。。。。。


  • 第二道菜

// 不借助toString,需要求值计算,参数有所限制
console.log(sumAll(1)(2)(3)) // 6
console.log(sumAll(1)(2, 3)) // 6

以下是具体实现

function sum(a,b,c){
    return a+b+c;
}
function curry(fn){
    const args = [...arguments].slice(1);
    return function(){
        const newArgs = args.concat([...arguments])
        if(newArgs.length<fn.length){
            return curry.apply(this,[fn,...newArgs])
        }else{
            return fn.apply(this,newArgs)
        }
    }
}
const sumAll = curry(sum)

首先,将sum传进去,我们需要知道一点fn.length用来计算参数的长度,像sum,三个参数,便是3.

本质上和上一个算法是没什么区别的,都是先收集参数,再触发求值的流程。

  1. 首先sum先传入到了curry内,arg此时为[], 返回了一个函数。sumAll开始接受参数了,第一个接受的参数为1,newArg便是[1],发现newArg的参数收集只有1个,小于sum的长度(3),然后执行一次curry递归,将sum和新的参数收集放进去。
  2. 现在收集参数2,返回函数中,将2送入,此时的newArg是[1, 2]。
  3. 收集参数3,返回函数中,发现已经满足求值的条件了,触发sum的求值函数,返回1 + 2 + 3 = 6