从优化一个js函数柯里化开始

286 阅读2分钟

维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

话不多说,上一个最简单的例子 实现add(1)(2)(3)为6

add(1,2,3)   // 6
写一个函数能使下面这个也成立
add(1)(2)(3)  //6

先直接上一版本最简单粗暴的方法

function curryingAdd(x) {
    return function (y) {
        return function(z){
            return x+y+z
    }
}
curryingAdd(1)(2)(3)   // 6

当然以上方法实在是很不优雅,而且对于如果是add(1)(2,3)这样的情况也无法处理啊!!!!

这个时候应该怎么办?

思考!!!

我们需要使函数一次调用传入多个参数到变成多次钓友每次传一个参数

我直接网上找了一个方法,差不多能符合这个要求的

const curry = fn => 
    judge = (...args) =>
        args.length >= fn.length
            ? fn(...args)
            : (...arg) => judge(...args, ...arg)


function fn(a,b,c) {
   return a+b+c
 }
const add = curry(fn)

add(1, 2, 3) // 6
add(1, 2)(3) // 6
add(1)(2)(3) // 6

看到这里,有的观众觉的差不多了,可以交卷了,但是不,不,不 这个方法还是不够完善,这个方法现在是写死了fn函数的参数,和第一种方法一样,根本不够灵活

比如我想执行add(1)(2),add(1)(2)(3)(4),都是不可以的,因为fn函数规定了传递的参数只能是四个,这个时候就是还是需要思考,应该让这个柯里化函数更加自由,更加智能 于是就出了第三版本的柯里化函数

function argsSum(args) {
        return args.reduce((per, cur) => {
          return per + cur;
        });
      }
function add(...arg1) {
    let sum1 = argsSum(arg1);
    let fn = function (...arg2) {
      if(arg2.length>0){
        let sum2 = argsSum(arg2);
        return add(sum1 + sum2);
      }else{
        return sum1
      }
    }
    fn.toString = function () {
      return sum1;
    };
    return fn;
  }
      
  let a = add(1, 2,3)  // 6
  let b = add(1)(2,3)  // 6
  let c = add(1)(2,3)(4)  // 10

  console.log("a", a);
  console.log("b", b);
  console.log("c", c);

这个时候就对传入参数没有限制了

如果你对函数式编程有一定了解,函数柯里化(function currying)是不可或缺的,利用函数柯里化,可以在开发中非常优雅的处理复杂逻辑。像比较常用的lodash工具库中就有很多封装好的函数式编程函数,柯里化函数。

参考

手写JS-函数柯里化 如何理解柯里化|函数式编程