可以理解为提前接收部分参数,延迟执行,不立即输出结果,而是返回一个接受剩余参数的函数。因为这样的特性,也被称为部分计算函数。柯里化,是一个逐步接收参数的过程。在接下来的剖析中,你会深刻体会到这一点。 反柯里化,是一个泛型化的过程。它使得被反柯里化的函数,可以接收更多参数。目的是创建一个更普适性的函数,可以被不同的对象使用。有鸠占鹊巢的效果。
实现 add(1)(2, 3)(4)() = 10 的效果 , 依题意,有两个关键点要注意:传入参数时,代码不执行输出结果,而是先记忆起来 当传入空的参数时,代表可以进行真正的运算
完整代码如下:
由于是延迟计算结果,所以要对参数进行记忆。
这里的实现方式是采用闭包。
当执行var add = currying(...)时,add变量已经指向了next方法。此时,allArgs在next方法内部有引用到,所以不能被GC回收。也就是说,allArgs在该赋值语句执行后,一直存在,形成了闭包。
依靠这个特性,只要把接收的参数,不断放入allArgs变量进行存储即可。
所以,当arguments.length > 0时,就可以将接收的新参数,放到allArgs中。
最后返回next函数指针,形成链式调用。
题意是,空参数时,输出结果。所以,只要判断arguments.length == 0即可执行。
另外,由于计算结果的方法,是作为参数传入currying函数,所以要利用apply进行执行。
综合上述思考,就可以得到以下完整的柯里化函数。
柯里化,在这个例子中可以看出很明显的行为规范:
实现 add(1)(2, 3)(4)(5) = 15 的效果。
很多人这里就犯嘀咕了:我怎么知道执行的时机?
其实,这里有个忍者技艺:valueOf和toString。
js在获取当前变量值的时候,会根据语境,隐式调用valueOf和toString方法进行获取需要的值。
那么,实现起来就很简单了。
有以下轻提示类。现在想要单独使用其show方法,输出新对象obj中的内容。
用反柯里化的方式,可以这么做
在上面的例子中,Toast.prototype.show方法,本来是Toast类的私有方法。跟新对象obj没有半毛钱关系。
经过反柯里化后,却可以为obj对象所用。
为什么能被obj所用,是因为内部将Toast.prototype.show的上下文重新定义为obj。也就是用apply改变了this指向。
而实现这一步骤的过程,就需要增加反柯里化后的objShow方法参数。
Function.prototype.unCurrying = function(){
var self = this;
return function(){
return Function.prototype.call.apply(self, arguments);
}
}
// 使用
var objShow = Toast.prototype.show.unCurrying();
objShow(obj);
这里的难点,在于理解Function.prototype.call.apply(self, arguments);。
可以分拆为两步:
1) Function.prototype.call.apply(...)的解析
可以看成是callFunction.apply(...)。这样,就清晰很多。
callFunction的this指针,被apply修改为self。
然后执行callFunction -> callFunction(arguments)
2) callFunction(arguments)的解析
call方法,第一个参数,是用来指定this的。所以callFunction(arguments) -> callFunction(arguments[0], arguments[1-n])。
由此可以得出,反柯里化后,第一个参数,是用来指定this指向的。
3)为什么要用apply(self, arguments)
如果使用apply(null, arguments),因为null对象没有call方法,会报错。
上述代码,用反柯里化,可以这么写:
其实,反柯里化和泛型方法一样,只是理念上有一些不同而已。理解这种思维即可。
理论计算机科学中,柯里化提供了在简单的理论模型中,比如:只接受一个单一参数的lambda演算中,研究带有多个参数的函数的方式。 函数柯里化的对偶是Uncurrying,一种使用匿名单参数函数来实现多参数函数的方法。
很多刚刚了解函数式编程的人会对偏函数应用(partial application)和柯里化(currying)之间的区别感到困惑。实际上,直到现在也很少在 JavaScript 中看到柯里化的实际使用,许多叫curry()的工具函数并不是柯里化函数。它们其实是偏函数!
如果我们需要设计一个函数来计算每个月的开销,在每天结束之前,我们需要记录当天花费了多少。在月底的时候计算出这个月一共开销了多少? 可以看出在性能上和方式二差不多,但是这样做更加通俗易懂了,当然在实际开发中,我们一般会封装为对象。
我们经常说在Javascript语言中,函数是“一等公民”,它们本质上是十分简单和过程化的。可以利用函数,进行一些简单的数据处理,return 结果,或者有一些额外的功能,需要通过使用闭包来实现,最后经常会return 匿名函数。
柯里化(Currying),又称部分求值(Partial Evaluation),是把接收多个参数的函数变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受剩余的参数而且返回结果的新函数的技术。
把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,并返回接受剩余的参数而且返回结果的新函数的技术。其由数学家Haskell Brooks Curry提出,并以curry命名。
最近在社区阅读技术博客的时候偶然间看到了函数柯里化几个字,还有要求手写js函数柯里化,心想是柯里化是什么高级的东西?没听说过啊?就带着问题出发,专门去学习了一下,做了一些整理。
函数式编程是一种如今比较流行的编程范式,它主张将函数作为参数进行传递,然后返回一个没有副作用的函数,说白了,就是希望一个函数只做一件事情。这种编程思想涵盖了三个重要的概念:
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的
很多同学都能看出来,这些写是非常傻的,因为函数f1和f是等效的,我们直接令var f1 = f;就行了,完全没有必要包裹那么一层。但是,下面一段代码就未必能够看得出问题来了:
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!