定义
柯里化是一种将使用多个参数的函数转为一系列使用一个参数的函数的技术。例如:
// 普通函数,带有两个参数
function add(a, b){
return a + b;
}
add(1, 2);
// 假设有一个柯里化函数curry
var addCurry = curry(add);
addCurry(1)(2);
作用
柯里化函数的作用可以理解成是参数复用。
// 假设有一个函数,内有三个参数
function ajax(type, url, data){
var xhr = new XMLHttpRequest();
xhr.open(type, url, data);
xhr.send();
}
// 发送请求
ajax('POST', 'www.test.com', "name=kevin")
ajax('POST', 'www.test2.com', "name=kevin")
ajax('POST', 'www.test3.com', "name=kevin")
// 利用curry
var ajaxCurry = curry(ajax);
var post = ajaxCurry('POST');
var postFromTest = post('www.test.com');
postFromTest("name=kevin");
手写Map
第一版
要实现以下功能:
function add(a, b){
console.log([a, b]);
}
var addCurry = curry(add, 1, 2);
addCurry(); // [1, 2]
var addCurry = curry(add, 1);
addCurry(2); // [1, 2]
var addCurry = curry(add);
addCurry(1, 2); // [1, 2]
所以可以判断出,传入的第一个参数是一个函数,然后内部返回一个新的函数,新函数内部拼接参数:
var curry = function(fn){
var args = Array.prototype.slice.call(arguments, 1);
return function(){
var newArgs = args.concat(Array.prototype.slice.call(arguments));
return fn.apply(this, newArgs);
}
}
第二版
有没有觉得这种写法很麻烦:
var test1 = curry(test, 1);
var test2 = test1(2);
var test3 = test2(3);
var test4 = test2(4);
// 如果可以这样写,那就很方便了
var test3 = curry(test, 1)(2)(3);
var test4 = curry(test, 1, 2)(4);
柯里化函数可以使用以下语法:
addCurry(1)(2); // [1, 2]
然而上面我们写的那一版会报错,我们可以多增加一个参数,测试一下其他写法,所以这一版我们要实现的功能如下:
function test(a, b, c){
console.log([a, b, c]);
};
var fn = curry(test);
fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]
第一版中我们使用了return fn.apply(this, newArgs);
直接将参数拼接然后执行该函数,而本次版本中可以看成:
- 如果传入的参数等于声明的函数的参数数量,那么可以直接执行函数;
- 如果传入的参数小于声明的函数的参数数量,那么返回该柯里化函数,支持继续添加新的参数。
function curry(fn ,args){
var len = fn.length; // 获得传入的函数定义的参数数量
args = args || [];
return function(){
var _args = args.slice(0);
for(let i = 0; i < arguments.length; i++){
let arg = arguments[i];
_args.push(arg);
}
if(_args.length < len){
return curry.call(this, fn, _args);
}else {
return fn.call(this, _args);
}
}
}
p.s 如果觉得自己封装柯里化函数太麻烦,可以使用lodash
中的curry
。
参考
- [函数式编程之柯里化和组合详解](https://segmentfault.com/a/1190000007328944);
- JavaScript专题之函数柯里化
若有错误,欢迎指出,感谢~