函数式编程最近越来越活跃,去年实习的时候买了一本 《JavaScript 函数式编程》,囫囵吞枣的看了一遍,似懂非懂的, 今年重新看了一遍,现写下这篇博客,谈谈我对柯里化的理解吧。
柯里化
柯里化函数为每一个逻辑参数返回一个新函数。(《JavaScript 函数式编程》)
简单说,函数柯里化就是对高阶函数的降阶处理。
举个例子,就是把原本:
function(arg1,arg2)变成function(arg1)(arg2)
function(arg1,arg2,arg3)变成function(arg1)(arg2)(arg3)
function(arg1,arg2,arg3,arg4)变成function(arg1)(arg2)(arg3)(arg4)
……
function(arg1,arg2,…,argn)变成function(arg1)(arg2)…(argn)
作者:小蝶惊鸿
链接:https://www.zhihu.com/question/40374792/answer/86268208
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
举个例子
一个参数
强制只接收一个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   |  function curry (fun) {   return function (arg) {     return fun(arg);   } }
 
  function curry (fun) {   return arg => fun(arg); }
  [1, 2, 3, 4, 5].map(parseInt)
 
  [1, 2, 3, 4, 5].map(curry(parseInt))
 
 
 
  | 
 
两个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
   |  function normalAdd(x, y) {   return x + y; }
 
  function add(y) {   return function(x) {     return x + y;   } }
  let add2 = add(2);
  add2(3);
 
 
  function normalMultiply(x, y) {   return x * y; }
 
  function multiply(y) {   return function(x) {     return x * y;   } }
  let multiply2 = multiply(2);
  multiply2(3);
 
 
  function curry2 (fun) {   return function (arg2) {     return function (arg1) {       return fun(arg1, arg2);     }   } }
 
  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);
 
  curryMultiply2(3);
 
 
 
  | 
 
三个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
   |  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);
 
 
 
  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]);
 
 
 
  function curry3 (fun) {   return function (last) {     return function (middle) {       return function (first) {         return fun(first, middle, last);       }     }   } }
 
  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]);
 
 
  | 
 
柯里化到底有什么用
每个步骤都是显性调用(消耗一个参数),同时将该步骤的结果缓存(返回匿名闭包,该闭包等待下一个参数),从而暂缓调用,待时机成熟时便可传入下一个参数以便继续调用;
两个参数情况下的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
   |     actionList = [{    "action": "isLogin",    "hasCallback": true    }, {    "action": "doLogin",    "hasCallback": false    }, {    "action": "setTitle",    "hasCallback": true  }];
     factory(actionList) {    for (let value of actionList) {      this[`${value.action}`] = this.generator(value);    }  }
     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);       });     }   }
 
     bridge.setTitle({skin: 'red', color: '#666'})    .then((data) => {       alert(data);    })    .catch((err) => {      alert(err);    });
 
   | 
 
三个参数情况下的应用
1 2 3 4 5
   |  export default function thunkMiddleware({ dispatch, getState }) {   return next => action =>     typeof action === 'function' ? action(dispatch, getState) : next(action); }
 
  | 
 
该中间件期待一个第一个参数 { dispatch, getState }, 并返回一个期待一个 next 参数的匿名函数, 由于 next 的值由上一个中间件决定, 因此暂缓调用, 直至传入 next 参数, 最终返回一个新的函数(即加入中间件的 dispatch 函数), 该函数期待一个 action 参数。
具体调用过程及原理详见:理解 redux 中间件
参考:
专属前端坑的函数式编程
深入到源码:解读 redux 的设计思路与用法
理解 redux 中间件