柯里化函数的实现

柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果。

如果要实现下面这个方法:

add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133

上面这个函数当参数为空的时候执行了内部参数所有值的相加,所以我们应该考虑当参数不为空的时候将缓存起来,在为空的时候再相加,这样的思路会用闭包的方式来实现。下面是实现方法:

function add () {
  // 用来缓存所有的arguments值  
  let args = [].slice.call(arguments);
  // 新建currying函数实现柯里化  
  let currying = function () {
    // 如果参数为空,那么递归停止,返回执行结果
    if (arguments.length === 0) {
      return args.reduce((a, b) => a + b);
    } else {
      // 否则将参数保存到args里面,返回currying方法
      args.push(...arguments);
      return currying
    }      
  }
  return currying
}
add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133

上面有需要注意的一点,因为currying函数里面使用arguments,所以currying不能使用箭头函数,箭头函数内部的arguments的用法与箭头函数内部的this差不多,它取的是上一级函数的arguments值。如果想用箭头函数,currying函数可以这样改动:

  let currying = (...rest) => {
    // 如果参数为空,那么递归停止,返回执行结果
    if (rest.length === 0) {
      return args.reduce((a, b) => a + b);
    } else {
      // 否则将参数保存到args里面,返回currying方法
      args.push(...rest);
      return currying
    }      
  }

我们返回的currying函数还可以使用callee来实现,原理相同,但是严格模式下不能使用:

function add () {
  // 用来缓存所有的arguments值  
  let args = [].slice.call(arguments);
  // 新建currying函数实现柯里化  
  return function () {
    // 如果参数为空,那么递归停止,返回执行结果
    if (arguments.length === 0) {
      return args.reduce((a, b) => a + b);
    } else {
      // 否则将参数保存到args里面,返回currying方法
      args.push(...arguments);
      return arguments.callee
    }      
  }
}
add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133

对普通函数进行柯里化:

// 柯里化函数的构造方法
function curry (fn) {
  // 缓存除第一个参数的所有参数
  let args = [].slice.call(arguments, 1);  
  let _fn = function () {
    if (arguments.length === 0) {
      return fn.apply(this, args)
    } else {
      args.push(...arguments);
      return _fn
    }
  }
  return _fn
}
function add () {
  return [].reduce.call(arguments, (a, b) => a + b)
}
console.log(curry(add, 2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)()) // 133
-----------不忘初心------------
原文地址:https://www.cnblogs.com/gaoht/p/14549528.html