实现函数柯里化,最后返回柯里化函数的时候为什么不需要额外传参?

Chor
  • 1.9k

在学习函数柯里化的时候看到这篇文章 https://github.com/yygmind/bl...
作者的一个实现思路是这样的:

function currying(fn, length) {
  length = length || fn.length;     // 注释 1
  return function (...args) {            // 注释 2
    return args.length >= length    // 注释 3
        ? fn.apply(this, args)            // 注释 4
      : currying(fn.bind(this, ...args), length - args.length) // 注释 5
  }
}

// Test
const fn = currying(function(a, b, c) {
    console.log([a, b, c]);
});

fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]

底下有一个评论说,"可以不用在递归 currying 的时候传入 length - args.length,因为 bind 返回的函数的 length 已经是 length - args.length 了",他给出的代码是:

function currying(fn) {
      return function (...args) {
        return args.length >= fn.length
          ? fn.apply(this, args)
          : currying(fn.bind(this, ...args))
      }
    }

为什么bind后返回的函数的形参个数,即length刚好是length - args.length呢?
这个length - args.length 我的理解是计算还需要多少个参数才可以实际运算fn,第一次递归后,currying的第二个参数就是这个差值,不再是函数形参个数,之后拿这个差值与柯里化后的函数实际接受的参数数目比较,如果这个数目达到了差值,就不需要再递归了。而按照这个评论的说法, bind 返回的函数的length就是length - args.length,因此不需要给递归的currying传length - args.length,这是怎么看出来的?bind的第二个参数会在bind返回的函数实际执行的时候传递给它,基于这一点我们才可以收集参数,最后统一运算,但是为什么bind返回的函数的length就刚好是length - args.length呢?

回复
阅读 1.5k
2 个回答
✓ 已被采纳

function.prototype.bind

bind 方法设置了返回的函数对象的 length 为 (输入的)fn.length - args.length

代码宇宙
  • 15.6k

bind的时候args展开的是实参,数量当然就是传入的实参数量。

这种写法只适用于es6,es5以前还是需要第一种写法。(虽然第一种写法也用到了参数展开,但是可以很容易改写成非展开的写法,而第二种则依赖于展开操作的副作用)

宣传栏