函数式编程最近越来越活跃,去年实习的时候买了一本 《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 中间件