摘要:不纯的函数充满的不确定性,在函数式编程中要尽量避免它。在以后的函数式编程中还会不断的遇见它的。
一.为什么需要柯里化(curry函数)
1.先简单的介绍一下纯函数
在函数式编程中纯函数是其最基本的思想,所谓纯函数就是一个相对不受外界影响(之所以说相对,是因为有的时候需要和外界沟通,函数没法保持所谓真正的纯,但后面会有方法来解决).在高中数学中都学过,函数是一种映射关系,在y=f(x)这个函数式中,每一个x都有一个与之对应的y值与它唯一对应。
说了这么多好像还是不是很明白,那就来个简单的例子:
//不纯的 var num=18 function foo1(enter) { if (enter>18) { console.log("wow") } } //纯的 function foo2(enter) { var num=18 if (enter>18) { console.log("wow") } }
两个函数实现的效果其实是一样的,但第一个函数不纯,第二个函数才是真的纯函数,它将num定义在函数体内,外界无法直接获取num,也无法改变它,相当于打雷天缩到了被窝,外面雷再大也跟我没关系了。
第一个函数之所以不纯是因为,它引用了函数体外的一个变量num,一旦你进行了外部引用,那这个函数的输出就不确定了。一旦num被改变了,那这个函数就不会按照你希望的执行下去了。不纯的函数充满的不确定性,在函数式编程中要尽量避免它。
纯函数中还有很多的好处,再此就不展开讨论了,以后有机会再详细的说说。
2.纯函数的一个使用场景
var add=x=>(y=>x+y)//为了更贴切函数式编程,这里用了ES6的写法,等价于下面的函数 // var add=function (x) { // return function(y) { // return x+y // } // } var add2=add(2) console.log(add2(1)) //3
这里使用闭包的方法,在add函数体内返回的匿名函数中有这样一句话:return x+y
它在匿名函数中保持着对x的引用,即使在垃圾回收中,x在执行上下文中已经被清理掉了,但还是能够凭借引用找到它,这就是闭包应用的简单的解释。
通过这样的写法,写函数变得更加灵活了。add2实际接受到是一个匿名参数,这个参数保留着第一次传入的参数。但你所需要的所有参数都传完(是的,可以有不止一个参数,但需要通过curry函数的帮助),再执行操作,也就是上述代码中x+y操作。
这样无论你想add10,还是add20,都很轻松了。
问题来了
这样写函数太挫了,而且太麻烦了,有没有什么好办法呢?答案是有,那就是今天的重头戏curry函数(通过curry函数处理一个函数的过程也叫柯里化)
先上代码:
//柯里函数实质:传递给函数一部分参数来调用它,让它返回一个函数来处理剩余参数 function curry(fx) { //要进行柯里化的函数的形参数量 var arity=fx.length return function f1() { //第一次传入的参数数量 var args=[].slice.call(arguments,0) //若传入的参数数量大于等于形参数量,代表现在万事俱备(参数齐全了),可以直接执行函数了,直接将参数全部传入fx函数中,并执行它 if (args.length>=arity) { return fx.apply(null,args) }else{ var f2=function() { //如果只传入了一部分参数 var args2 = [].slice.call(arguments, 0) //判断是否所有参数都传完了,如果没有,不断concat新传的参数,然后执行f1函数 return f1.apply(null, args.concat(args2)) } return f2 } } }
其实看书看到这部分的时候作者直接用lodash库中的curry,看的十分蛋疼,觉得没有详细的代码总归不能理解的透彻。结果点开github上的作业(这本书有习题,就在GitHub上),发现有curry函数的实现。看了一圈有些小的不太理解的地方修改了一下,成了现在看到的函数。
现在就可以用curry了,用起来也是十分舒服(偷懒直接上书上代码):
var match = curry(function(what, str) { return str.match(what); }); var replace = curry(function(what, replacement, str) { return str.replace(what, replacement); }); var filter = curry(function(f, ary) { return ary.filter(f); }); var map = curry(function(f, ary) { return ary.map(f); }); match(/s+/g, "hello world"); // [ " " ] match(/s+/g)("hello world"); // [ " " ] var hasSpaces = match(/s+/g); // function(x) { return x.match(/s+/g) } hasSpaces("hello world"); // [ " " ] hasSpaces("spaceless"); // null filter(hasSpaces, ["tori_spelling", "tori amos"]); // ["tori amos"] var findSpaces = filter(hasSpaces); // function(xs) { return xs.filter(function(x) { return x.match( /s+/g) }) } findSpaces(["tori_spelling", "tori amos"]); // ["tori amos"]
这样是不是就能感受到curry的强大之处呢。在以后的函数式编程中还会不断的遇见它的。
(写在最后,关于curry函数实现的一点小问题,使用ES6的箭头函数更贴切函数式编程的思想,但是箭头函数无法识别arguments对象,所以还是老老实实写匿名函数把)
(本文属于读书笔记,看的书是js函数式编程,在gitbook上就能看到)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/89960.html
摘要:函数式编程,一看这个词,简直就是学院派的典范。所以这期周刊,我们就重点引入的函数式编程,浅入浅出,一窥函数式编程的思想,可能让你对编程语言的理解更加融会贯通一些。但从根本上来说,函数式编程就是关于如使用通用的可复用函数进行组合编程。 showImg(https://segmentfault.com/img/bVGQuc); 函数式编程(Functional Programming),一...
摘要:而函数式编程中,则认为数据只是行为加工的产品。我们会发现,在函数式编程中,我们去除掉了主语。下面就来说说函数式编程的一些具体的东西。纯函数在函数式编程中,有一个很重要的概念是纯函数。 JavaScript是一门很神奇的语言,作为一门现代化的语言,他有很多很有特色的东西,这些东西,让我们看到了一个十分自由化的未来,你永远都不知道,自己是不是掌握了这门奇葩的要命的语言。本文,可能没有那么多...
摘要:但是,对函数式编程而言,这个行为的重要性是毋庸置疑的。关于该模式更正式的说法是偏函数严格来讲是一个减少函数参数个数的过程这里的参数个数指的是希望传入的形参的数量。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTML 最坚实的梁柱;分享,是...
摘要:译者团队排名不分先后阿希冬青萝卜萌萌轻量级函数式编程第章融会贯通现在你已经掌握了所有需要掌握的关于轻量级函数式编程的内容。回头想想我们用到的函数式编程原则。这两个函数组合成一个映射函数通过,这就是融合见第章。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着沪江血液的纯粹工程:...
阅读 3101·2021-11-08 13:18
阅读 2247·2019-08-30 15:55
阅读 3581·2019-08-30 15:44
阅读 3027·2019-08-30 13:07
阅读 2758·2019-08-29 17:20
阅读 1910·2019-08-29 13:03
阅读 3382·2019-08-26 10:32
阅读 3201·2019-08-26 10:15