JavaScript 进阶营

javascript高阶函数应用——柯里化

2019-08-10  本文已影响4人  成熟稳重的李先生

高阶函数:
在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
1.接受一个或多个函数作为输入:forEach sort map filter reduce
2.输出一个函数:lodash.curry
不过它也可以同时满足两个条件:Function.prototype.bind

这里对高阶函数不过多讲解,这节我们来学习柯里化。

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术 。在直觉上,柯里化声称“如果你固定某些参数,你将得到接受余下参数的一个函数”。所以对于有两个变量的函数yx,如果固定了 y = 2,则得到有一个变量的函数 2x——柯里化·百度百科

由以上,我们来一段代码

// 假设我们要写一个+1的函数
function sum(x, y){
    return x+y
}
//此时,这个sum就称为对于x和y的函数
sum(1, 2)  // 3
//由柯里化的概念,我们可以固定一个参数,使后续操作可以只传一个参数
function addOne(y){
  return 1+y
}
addOne(2) //3
addOne(7) //8

//可如果,又有一个+2的需求呢,那好,我再写一遍
function addTwo(a){
  return a+2
}
addTwo(3) //5

//那再有+3,+4的需求呢? 

这时,我们就可以使用柯里化来简便这个过程,柯里化是惰性求值的,即在你需要的到值的时候,再取值。
这里借鉴一下《JavaScript设计模式与开发实践》书中的例子

假设我们要编写一个计算每月开销的函数。在每天结束之前,我们都要记录今天花掉了多少钱。代码如下:

var monthlyCost = 0; 
var cost = function( money ){ 
 monthlyCost += money; 
}; 
cost( 100 ); // 第 1 天开销
cost( 200 ); // 第 2 天开销
cost( 300 ); // 第 3 天开销
//cost( 700 ); // 第 30 天开销
alert ( monthlyCost ); // 输出:600

通过这段代码可以看到,每天结束后我们都会记录并计算到今天为止花掉的钱。但我们其实并不太关心每天花掉了多少钱,而只想知道到月底的时候会花掉多少钱。也就是说,实际上只需要在月底计算一次。如果在每个月的前 29 天,我们都只是保存好当天的开销,直到第 30 天才进行求值计算,这
样就达到了我们的要求。

以上需求,我们就可以利用柯里化的思想来惰性求值,先将一部分参数存起来,当我们实际需要值的时候再来求值,虽然下面的 cost 函数还不是一个 currying 函数的完整实现,但有助于 我们了解其思想。

var cost = (function(){ 
    var args = []; 
    return function(){ 
        if ( arguments.length === 0 ){ 
            var money = 0; 
            for ( var i = 0, l = args.length; i < l; i++ ){ 
                money += args[ i ];
            }
            return money;
        }else{
             [].push.apply(args, arguments)
            //或者 args = args.concat([].slice.call(arguments))
        }
    }
})()
cost(100)
cost(253)
cost()  // 353

接下来,我们要写一个正式的curry函数

// 第一个参数是我们需要柯里化的原函数,同时,在它后边你还可以传入一些初始的值。
//这里,你可以注明形参(只传fn的话),因为考虑到初始值的问题,我们就以arguments来代替了
var currying = function( fn ){ // 参数为原函数
       var args = []; 
       return function(){   // 柯里化后的新函数
           if ( arguments.length === 0 ){  // 参数数数量为0时,意为求值
               return fn.apply( this, args ); 
           }else{     // 否则,将这些值保存起来
               [].push.apply( args, arguments ); 
               return arguments.callee; 
           } 
       } 
};
var cost = (function(){ 
       var money = 0; 
       return function(){ 
           for ( var i = 0, l = arguments.length; i < l; i++ ){ 
               money += arguments[ i ]; 
           } 
           return money; 
       } 
})();
var cost = currying( cost ); // 转化成 currying 函数
cost( 100 ); // 未真正求值
cost( 200 ); // 未真正求值
cost( 300 ); // 未真正求值
alert ( cost() ); // 求值并输出:600

至此,我们就完成了对柯里化的初步了解

上一篇下一篇

猜你喜欢

热点阅读