# 定义
把接受多个参数的函数转换成接受一个单一参数的函数。
举个例子:
var add = function(x, y) {
return x + y;
}
add(3, 4) // 7
var foo = function(x) {
return function(y) {
return x + y
}
}
foo(3)(4) // 7
原本的add函数是接收两个参数的,可以将它写成函数foo的格式,每次调用只接收一个参数,这就是柯里化达到的目的,随后会讲这么做的好处。如果需要接受3个参数,就可以写成这样:
var foo = function(x) {
return function(y) {
return function(z) {
return x + y + z
}
}
}
foo(3)(4)(5) //7
那如果需要传入多个参数,这样的层层嵌套显然是不优雅的,接下来介绍一下一种更为通用的实现。
# 实现
var curry = function(f) {
var len = f.length
var args = []
return function t() {
// args.push(Array.prototype.slice.call(arguments))
[].push.apply(args, [].slice.apply(arguments))
if (args.length >= len) {
console.log(args)
return f.apply(undefined, args)
} else {
return t
}
}
}
function add (x, y, z) {
return x + y + z
}
var sum = curry(add)
console.log(sum(1)(2)(3)) // 6
注意内层函数t中的if语句,args是我们在外层函数定义的一个数组变量,用于保存参数,args.length >= len说明接收的参数已经和传入的函数f所需要的参数个数一致了,这个时候就可以执行函数f了。需要注意函数t内被我注释掉的一行,这一行之所以不能写,是因为call和apply的区别,apply的第二个数组就是一个数组,args.push(Array.prototype.slice.call(arguments))实际上是将一个数组对象push进了args中,这样调用add的时候实际输出为“123”。
# 作用
- 延迟计算(上面例子)
- 参数复用(例如:正则判断邮箱地址、手机格式)
- Funtion.prototype.bind也是函数柯里化实现的
- 动态创建函数
var addEvent = function(el, type, fn, capture) {
if (window.addEventListener) {
el.addEventListener(type, function(e) {
fn.call(el, e);
}, capture);
} else if (window.attachEvent) {
el.attachEvent("on" + type, function(e) {
fn.call(el, e);
});
}
};
这个函数意味着,每一次调用addEvent都要执行一次if else,通过函数柯里化可以只需要执行一次:
var addEvent = (function(){
if (window.addEventListener) {
return function(el, sType, fn, capture) {
el.addEventListener(sType, function(e) {
fn.call(el, e);
}, (capture));
};
} else if (window.attachEvent) {
return function(el, sType, fn, capture) {
el.attachEvent("on" + sType, function(e) {
fn.call(el, e);
});
};
}
})();