摘要:而柯里化是一个属于函数式编程的一个常见的技巧。简单来说,函数柯里化就是对高阶函数的降阶处理。让你意外的是,这就是柯里化的基本思想,简单地让人猝不及防。
函数式编程是一种被部分JavaScript程序员推崇的编程风格,更别说 Haskell 和 Scala 这种以函数式为教义的语言。原因是因为其能用较短的代码实现功能,如果掌握得当,能达到代码文档化(代码本身具有很高可读性甚至可以代替文档)的效果,当然,泛滥使用也会使代码可读性变差。
而柯里化(Currying)是一个属于函数式编程的一个常见的技巧。简单来说,函数柯里化就是对高阶函数的降阶处理。
我们看下面这个函数:
function loc (a,b,c){ console.log(a+"-"+b+"-"+c); } loc("浙江","杭州","西湖区");//>>>浙江-杭州-西湖区
这是一个接收三个地名字符串的函数,功能是将三个地名字符串拼接到一起成为一个详细的地址。
我们试试只传入两个参数:
loc("浙江","杭州");//>>>浙江-杭州-undefined
毫无疑义地,这个函数还是会正常执行,只是原本属于“区”的位置由于没有接收到参数而成了undefined。
其实这种情况很多,比如我们还要生成浙江-杭州-余杭区,浙江-杭州-拱墅区这样的地名,但是我们没必要每次都重新把浙江-杭州重新拼接一遍,所以你是不是会想,能不能只通过一个函数,把已经拼接过的字符串缓存起来,只去拼接新的字符串呢?我们或许可以把之前的函数改一下:
function loc (a) { return function(b){ return function(c){ console.log(a+"-"+b+"-"+c); } } }
好奇怪!这个loc函数只接收一个参数,而返回一个新的函数,这个函数也只接受一个参数,里面同样返回一个函数,最后一个函数才返回三个参数拼接的字符串。
看起来是一个嵌套关系,好吧,让我们看看它是否能实现刚刚的想法:
var Zhejiang = loc("浙江"); var Hangzhou = Zhejiang("杭州"); var Xihu = Hangzhou("西湖区"); //浙江-杭州-西湖区 var Yuhang = Hangzhou("余杭区"); //浙江-杭州-余杭区 var Lucheng = Zhejiang("温州")("鹿城区"); //浙江-温州-鹿城区
看,通过这样的形式,我们轻松实现定制化函数啦!loc("杭州")不会急着把地名都拼接好,而是把杭州先存到闭包中,在需要拼接的时候才用到它。
让你意外的是,这就是柯里化的基本思想,简单地让人猝不及防。
不,这不是你想要的结果,至少你已经考虑到一种恐怖的情况:如果参数有许多——比如100个,是不是要写一个嵌套一百次的函数?
好在,我们可以写一个通用函数来优雅地创建柯里化函数:
function curry(fn) { var outerArgs = Array.prototype.slice.call(arguments, 1); return function() { var innerArgs = Array.prototype.slice.call(arguments), finalArgs = outerArgs.concat(innerArgs); return fn.apply(null, finalArgs); }; }
有了这个基本函数之后,我们可以柯里化其他普通函数:
//一个普通函数 function loc(a,b,c){ console.log(a+"-"+b+"-"+c); } var workIn = curry(loc,"浙江","杭州","余杭区"); workIn();// >>> 浙江-杭州-余杭区
当然也可以这样定制:
var zj = curry(loc,"浙江"); var city = curry(zj,"杭州"); city("余杭区"); //>>> 浙江-杭州-余杭区 city("上城区"); //>>> 浙江-杭州-上城区 zj("温州","鹿城区");//>>> 浙江-温州-鹿城区
简直优雅。
以下我们来简单分析以下这个通用函数:
function curry(fn) { var outerArgs = Array.prototype.slice.call(arguments, 1); return function() { var innerArgs = Array.prototype.slice.call(arguments), finalArgs = outerArgs.concat(innerArgs); return fn.apply(null, finalArgs); }; }
我们看这个curry函数,显示接受一个参数,那就是需要被柯里化的函数。同时,因为JS神奇的函数传参,我们可以在curry继续放更多的参数,这些参数在函数体内部将以参数列表的形式存在,你可以通过arguments引用这个参数列表。注意,arguments引用的是一个参数列表而不是数组(虽然很像),所以数组的很多方法它都没有。当然,这个难不倒我们,还记得我上一篇文章里提到的apply()黑科技吗?传送门:《快速理解JavaScript中apply()和call()的用法和用途》
outerArgs就是获取除了第一个参数之外的参数列表。
而在返回的函数里,innerArgs获取的是调用这个返回函数时传入的所有参数,比如之前city("上城区")里面的"上城区"。
而finalArgs则是拼接这两个数组(注意此时两个参数列表都已经是正宗的数组,所以才可以使用concat方法)。
最后,使用apply,把所有参数组成的列表传入到原来的函数,其实质就是在调用原始的函数,因为此时的参数都已齐全。
结尾福利:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/78887.html
摘要:函数式编程,一看这个词,简直就是学院派的典范。所以这期周刊,我们就重点引入的函数式编程,浅入浅出,一窥函数式编程的思想,可能让你对编程语言的理解更加融会贯通一些。但从根本上来说,函数式编程就是关于如使用通用的可复用函数进行组合编程。 showImg(https://segmentfault.com/img/bVGQuc); 函数式编程(Functional Programming),一...
摘要:以案例中的漏洞为例,安骑士的修复建议功能通过漏洞真实影响分析,能快速计算出漏洞真实受到影响较大的机器,在非常短的时间内给出企业修复排序的有效建议。 摘要: 关注网络安全的企业大都很熟悉这样的场景:几乎每天都会通过安全媒体和网络安全厂商接收到非常多的漏洞信息,并且会被建议尽快修复。尽管越来越多的企业对网络安全的投入逐年增加,但第一时间修复所有漏洞,仍然是一件非常有挑战的事。 关注网络安全...
摘要:原文链接和都支持函数的柯里化函数的柯里化还与的函数编程有很大的联系如果你感兴趣的话可以在这些方面多下功夫了解相信收获一定很多看本篇文章需要知道的一些知识点函数部分的闭包高阶函数不完全函数文章后面有对这些知识的简单解释大家可以看看什么是柯里化 原文链接 Haskell和scala都支持函数的柯里化,JavaScript函数的柯里化还与JavaScript的函数编程有很大的联系,如果你感兴...
摘要:作为函数式编程语言,带来了很多语言上的有趣特性,比如柯里化和反柯里化。在一些函数式编程语言中,会定义一个特殊的占位变量。个人理解不知道对不对延迟执行柯里化的另一个应用场景是延迟执行。不断的柯里化,累积传入的参数,最后执行。作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。 这里可以对照另外一篇介绍 JS 反柯里化 的文章一起看~ 1. 简介 柯里化(Currying)...
摘要:作为函数式编程语言,带来了很多语言上的有趣特性,比如柯里化和反柯里化。而反柯里化,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。 可以对照另外一篇介绍 JS 柯里化 的文章一起看~ 1. 简介 柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩...
阅读 3010·2021-11-24 10:47
阅读 3796·2021-11-02 14:43
阅读 2204·2021-09-26 10:15
阅读 2177·2021-09-08 09:35
阅读 531·2019-08-30 12:45
阅读 2750·2019-08-29 17:04
阅读 3197·2019-08-26 14:05
阅读 1239·2019-08-26 12:10