一次性了解柯里化——javascript

什么是柯里化?

柯里化(Currying),又称部分求值(Partial Evaluation),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
在这里插入图片描述

柯里化的核心思想是:降低通用性,提高适用性。
比如下面的代码,由 通用性高 逐渐变为 适用性高
在这里插入图片描述

柯里化有3个常见作用:

1. 参数复用

假设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

2. 提前返回

兼容现代浏览器以及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);

3. 延迟计算/运行

延迟计算的例子,比如统计分数,
普通写法:

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元函数

猜你喜欢

转载自blog.csdn.net/HYeeee/article/details/88243789