阅读 101

柯里化是什么?JavaScript 中如何实现add(1)(2)(3)(...)

柯里化的英文叫currying,没错,他也是以一个人名来命名的,这位老爷子叫Haskell Brooks Curry,但是猛地一看,有三个语言也是以他的名字命名的,分别就是Haskell、Brooks、Curry。

image.png

再来说什么是柯里化,柯里化是一种函数式技术,就是当一个函数不是一次接受所有参数,而是接受第一个参数并返回一个接受第二个参数的新函数,如果需要在返回一个接受第三个参数的新函数,依此类推,直到所有参数都得到了处理。

如现在有以下函数。

function sum(a, b, c) {
    return a + b + c;
}
复制代码

按照上面所说,柯里化技术就不能接收全部参数,而是像下面这样。

function sum(a) {
    return (b) => {
        return (c) => {
            return a + b + c
        }
    }
}

console.log(sum(1)(2)(3)) // 6
复制代码

这看起来很好理解,但是事实上就是很好理解,如果我们通过typeof来查看sum(1)返回什么类型的时候,那它一定会输出function。

console.log(typeof sum(1))
复制代码

另外还可以这样写。

const add = x => y => x+y;
复制代码

但是问题不是在这,问题是如何实现一个无限累积的函数,我们总不能需要n个参数,就写n个函数吧。

我们可以这样写,首先在add函数内部定义一个sum变量,让他的返回值是一个函数resultFn,而resultFn函数的返回值又是自己,这就可以一直在后面调用,那么结果怎么办?这就需要提前保存下来,也就是resultFn.result。

function add(x) {
  let sum = x;
  return function resultFn(y) {
      sum += y;
      resultFn.result = sum;
      return resultFn;
  }
}
复制代码

最后直接对函数调用.result即可获取结果。

还可以这样写,这个原理是利用callee,在函数内部有两个特殊的对象,arguments和 this。arguments保存这函数参数, 他有个叫 callee 的属性,该属性是一个指针,指向含当前正在执行的函数。

通过typeof add(1)查看输出时候结果是function,关键在于,如何得到结果,就是判断最后一个括号中的值,如果什么也不传,那么typeof y !== 'undefined'便不成立,直接返回x。

 function add(x) {
            return function (y) {
                if (typeof y !== 'undefined') {
                    x = x + y;
                    return arguments.callee;
                } else {
                    return x;
                }
       };
}

console.log(add(2)(2)(3)())
复制代码
文章分类
前端
文章标签