柯里化是指这样一个函数(假设叫做createCurry),他接收函数A作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。

柯里化函数为每一个逻辑参数返回一个新函数。(《JavaScript 函数式编程》)

这样的定义可能不太好理解,我们可以通过下面的例子配合理解。

一个参数

// 接收一个参数自动柯里化
function curry (fun) {
  return function (arg) {
    return fun(arg);
  }
}

// es6 装逼版
function curry (fun) {
  return arg => fun(arg);
}

[1, 2, 3, 4, 5].map(parseInt)
//[1, NaN, NaN, NaN, NaN]

[1, 2, 3, 4, 5].map(curry(parseInt))
//[1, 2, 3, 4, 5]

两个参数

// 普通二参数的加法
function normalAdd(x, y) {
  return x + y;
}

// 柯里化版本
function add(y) {
  return function(x) {
    return x + y;
  }
}

let add2 = add(2);

add2(3);
// 5

// 普通二参数乘法
function normalMultiply(x, y) {
  return x * y;
}

// 柯里化版本
function multiply(y) {
  return function(x) {
    return x * y;
  }
}

let multiply2 = multiply(2);

multiply2(3);
// 6

// 自动柯里化
function curry2 (fun) {
  return function (arg2) {
    return function (arg1) {
      return fun(arg1, arg2);
    }
  }
}

// es6 装逼版
function curry2 (fun) {
  return arg2 => arg1 => fun(arg1, arg2);
}

let curryAdd = curry2(normalAdd);
let curryAdd2 = curryAdd(2);

let curryMultiply = curry2(normalMultiply);
let curryMultiply2 = curryMultiply(2);

curryAdd2(3);
// 5

curryMultiply2(3);
// 6

三个参数

// 普通版本
function normalAddThenMultiply(arr, factor, increase) {
  let tempArr = arr.map(function(ele, index) {
    return normalAdd(ele, increase);
  });

  return tempArr.map(function(ele, index) {
    return normalMultiply(ele, factor);
  });
}

normalAddThenMultiply([1, 2, 3], 3, 2);
// [9, 12, 15]


// 柯里化版本
function addThenMultiply(increase){
    return function(factor) {
      return function(arr) {
        let addStep = curry2(normalAdd);
        let multiplyFactor = curry2(normalMultiply);
        let tempArr = arr.map(addStep(increase));
        return tempArr.map(multiplyFactor(factor));
      }
    }
  }

let add2Multiply = addThenMultiply(2);

let add2Multiply3 = add2Multiply(3);

add2Multiply3([1, 2, 3]);
// [9, 12, 15]


// 自动柯里化
function curry3 (fun) {
  return function (last) {
    return function (middle) {
      return function (first) {
        return fun(first, middle, last);
      }
    }
  }
}

// es6 装逼版
function curry3(fun) {
  return last => middle => first => fun(first, middle, last);
}

let curryAddMultiply = curry3(normalAddThenMultiply);
let curryAdd2Multiply = curryAddMultiply(2);
let curryAdd2Multiply3 = curryAdd2Multiply(3);

curryAdd2Multiply3([1, 2, 3]);
// [9, 12, 15]

柯里化到底有什么用

每个步骤都是显性调用(消耗一个参数),同时将该步骤的结果缓存(返回匿名闭包,该闭包等待下一个参数),从而暂缓调用,待时机成熟时便可传入下一个参数以便继续调用;

两个参数情况下的应用

// 用于定义一系列 action
 actionList = [{
   "action": "isLogin",
   "hasCallback": true
   }, {
   "action": "doLogin",
   "hasCallback": false
   }, {
   "action": "setTitle",
   "hasCallback": true
 }];

 // 批量生成 API 的工厂函数
 factory(actionList) {
   for (let value of actionList) {
     this[`${value.action}`] = this.generator(value);
   }
 }

 // 简化版本的 API 生成函数
 generator(action) {
    return function(params) {

      let MyPromise = es6Promise.Promise;

      action['params'] = params;

      return new MyPromise((resolve, reject) => {
        let callbackId = this.generateId();
        this.responseCallbackList[callbackId] = (data) => {
          resolve(data);
        }
        this.sendAction(action, callbackId);
      });
    }
  }

// 最终的调用方式, 其中 params 是用户调用时才传入的
   bridge.setTitle({skin: 'red', color: '#666'})
   .then((data) => {
      alert(data);
   })
   .catch((err) => {
     alert(err);
   });

三个参数情况下的应用

// redux-thunk 中间件
export default function thunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === 'function' ? action(dispatch, getState) : next(action);
}