柯里化(Currying),又称部分求值(Partial Evaluation),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
柯里化的核心思想是:降低通用性,提高适用性。
比如下面的代码,由 通用性高 逐渐变为 适用性高
假设a,b大多数情况是固定的,只有C每次都变,这样只需要更改add2()中的参数即可计算a+b+x的值。
如果传参a,b的函数中需要做大量计算,那么用柯里化在这里提高了性能。
(如果a、b总是固定,直接写死,但这里不是总是固定的)
function add(a){
//...大量计算
return function(b){
//...大量计算
return function(c){
console.log(a+b+c);
}
}
}
//add(1)(2)(3) //6
const add1 = add(1);
const add2 = add1(2);
add2(3); //6
兼容现代浏览器以及IE浏览器的事件添加方法。我们正常情况可能会这样写:
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(p,click,callback,true);
addEvent(div,click,callback,true);
addEvent(span,click,callback,true);
这里存在的问题是,我们只需要判断一次浏览器就可以了,后面两次的判断完全没必要,利用柯里化,修改代码如下:
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);
});
};
}
};
var elBindEvent = addEvent(); //这里执行浏览器判断
elBindEvent (p,click,callback,true); //只执行返回的函数
elBindEvent (div,click,callback,true);
elBindEvent (span,click,callback,true);
延迟计算的例子,比如统计分数,
普通写法:
var allScore = 0;
var addScore = function(score) {
allScore += score ;
};
addScore(2);
addScore(6.5);
addScore(1.5);
console.log(allScore); //10
柯里化:每次的分数放入数组中,最后一次计算数组的和,这样写的对性能感觉没啥影响,就是输入的参数可以是任意个。
var allScore = 0;
var curryScore = function() {
var arrayScore = [];
return function(){
if(arguments.length === 0){
//只有当不传参时,才进行计算
for(i in arrayScore){
allScore += arrayScore[i];
}
}else{
//每个分数放入数组中
arrayScore = arrayScore.concat([].slice.call(arguments));
}
}
};
var addScore = curryScore();
addScore(2);
addScore(6.5);
addScore(1.5,5);
addScore(); //计算
console.log(allScore); //输出
三个作用都体现了的版本
var curry = function(fn) {
var __array = [];
return function comm(){
if(arguments.length === 0){
//处理函数通过参数调用,将数组传给处理函数
return fn.apply(null,__array);
}
Array.prototype.push.apply(__array, [].slice.call(arguments));
return comm; //链式调用,为了体现1:参数复用,实现()()()的效果。
}
};
//自定义处理函数:这里假设是两个数相加
function deal(a,b){
console.log(a+b);
}
var addScore = curry(deal); //体现了2:提前返回
addScore(2)(5); //不会计算,只会存
addScore(2)(5)(); //7 实现3:延迟计算
柯里化是由N元函数转化成1元函数
偏函数是由N元函数转化成N-1元函数