柯里化是指这样一个函数(假设叫做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);
}