JavaScript编程之函数柯里化

柯里化(Currying)

维基百科定义:

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

从一个例子理解合理化

有点复杂,简单表达:

函数柯里化(curry)可以简单的理解是将具有多个参数的函数,转换成具有较少的参数的函数的过程,具体将具有多个参数的函数转换成一系列嵌套函数,使用一部分参数调用柯里化函数返回一个新函数,每次返回的函数处理剩余的参数。

function multiplyabc{ 
    return a * b * c; 
}

multiply2,2,5// 20

这个简单的函数定义了三个参数,参数相乘返回运算结果。

我们将上面的函数重构成柯里化结构的函数,用以说明柯里化的使用方法。

function multiplyabc{ 
    return a=> {
      return  b=> {
        return c => {
          return a * b * c;
        }
      }
    }
}

multiply(2)(2)(5) // 20

通过柯里化函数,我们将一个功能改造成一系列的功能,将之前需要一次传递的多个参数,分为三次传递,每次传递的函数作为下一个函数的内链调用。

为了便于理解函数柯里化的调用,我们可以将上面的柯里化函数multiply(2)(2)(5) 调用过程分开书写。

const multiply_fir = multiply(2);
const multiply_sec = multiply_fir(2);
const result = multiply_sec(5);

console.log(result ); // 20

柯里化的应用

柯里化函数是函数式编程的一种很实用的实践。函数式编程是一种重要的编程范式,最重要的特点是函数作为第一等公民,并且强调函数本身的纯粹性,对于相同的输入参数返回相同的结果没有其他副作用。

所以我们创建的柯里化函数本身是一个纯函数,并且具有自己的特征,可以创建有意义的代码模块。

1. 代码的复用

当我们的函数参数大部分情况下相同的时候,我们可以利用柯里化解决公共参数复用的问题。

const obj = { name: 'test' };
const foo = function (prefix, suffix) {
    console.log(prefix + this.name + suffix);
}.bind(obj, 'currying-');

foo('-function'); // currying-test-function

2. 函数的合成(Compose)

如果一个值要经过多个函数,才能变成另外一个值,就可以把所有中间步骤合并成一个函数,这叫做”函数的合成”(compose)

const compose = function (f, g) {
  return function (x) {
    return f(g(x));
  };
}

3. 减少代码的中间变量

通过封装一系列处理步骤,可以减少对中间变量的操作,也是一种代码复用。比如我们需要操作一个数组,返回的对象是原数组每个元素上+1后的新的数组,这个需求很简单:

const list = [0, 1, 2, 3];
const list1 = list.map(elem => elem + 1); // => [1, 2, 3, 4]

当我们需求发生变化,需要增加+2的操作结果:

const list = [0, 1, 2, 3];
const list1 = list.map(elem => elem + 1); // => [1, 2, 3, 4]
const list2 = list.map(elem => elem + 2); // => [2, 3, 4, 5]

我们在维护这样一系列的代码的时候,很容易想到将list.map(elem => elem + 2)这样一个过程,进行封装,我们只需要传递我们需要操作的参数即可,这样可以提高代码的可读性。 我们的代码结构如下:

const plus1 = plus(1);
const plus2 = plus(2);

const list = [0, 1, 2, 3];
const list1 = list.map(plus1); // => [1, 2, 3, 4]
const list2 = list.map(plus2); // => [2, 3, 4, 5]

我们只需要实现plus()函数即可完成代码的封装,提高代码的维护性和可读性,JS柯里化可以实现我们的需求。

function plus(a) {
  return function(b) {
    return a + b;
  }
}   

参考

Mark24

Everything can Mix.