前言本文共1454字,阅读时间约4分钟。摘要:本文从初学者的角度阐述了Javascript中柯里化的概念以及如何在工作中使用它。原文地址:了解Javascript之柯里化知乎专栏:前端攻击博主博客地址:Damonare的个人博客。函数式编程是当今流行的编程范式。它提倡将函数作为参数传递,然后返回一个没有副作用的函数。说白了就是希望一个函数只能做一件事情。Javascript、Haskell、Clojure等编程语言都支持函数式编程。这种编程思想涵盖了三个重要的概念:纯函数柯里化高阶函数,本文主要想给大家解释一下柯里化的概念。什么是柯里化首先我们来看一个例子:functionsum(a,b,c){returna+b+c;}//Callsum(1,2,3);//6以上函数的实现就是把a,b,c三个参数相加,改写成柯里化函数如下:functionsum(a){returnfunction(b){returnfunction(c){返回a+b+c;}}}//调用letsum1=sum(1);让sum2=sum1(2);总和2(3);//6所谓柯里化,就是将参数较多的函数转换为参数较少的函数的过程。让我们一步步看看上面柯里化函数做了什么。首先,第一步调用sum(1)。此时变量sum1等价于:sum1=function(b){returnfunction(c){//注意这个当闭包中存在变量a时,才可以调用,a=1returna+b+C;}}然后调用sum1(2),此时赋值给变量sum2相当于:sum2=function(c){//变量a,b都在闭包中,a=1,b=2returna+b+c;}最后调用sum2(3),返回1+2+3的结果6;这是最简单的柯里化函数,是不是很简单?curried函数的作用那么问题来了。与原函数相比,上面重写的柯里化函数代码多了很多,而且不像原函数那么容易理解。柯里化函数有什么用?的确,这里的柯里化函数确实显得臃肿不实用,但在很多场景下却非常有用,很多人已经在不经意间使用柯里化函数了。举个简单的例子:假设我们有一批长方体,我们需要计算这些长方体的体积,实现如下函数:functionvolume(length,width,height){returnlength*width*height;}volume(200、100、200);体积(200、150、100);体积(200、50、80);体积(100、50、60);如上计算长方体的体积函数,你会发现有很多长方体的长度是一样的,我们用Curry变换函数来实现:functionvolume(length,width,height){returnfunction(width){返回函数(高度){返回长度*宽度*高度;}}}设len200=体积(200);len200(100)(200);len200(150)(100);len200(50)(80);体积(100)(50)(60);如上,通过实现一个len200函数,我们统一处理了一个长度为200的长方体的体积,实现了参数复用。让我们再举一个只执行一次函数的例子:functionexecOnce(fun){letflag=true;returnfunction(){if(flag){fun&&fun();标志=假;}}}letonceConsole=execOnce(function(){console.log('只打印一次');});onceConsole();onceConsole();如上,我们实现了一个execOnce函数,它接受一个函数参数,然后返回一个函数,变量flag存在于闭包中,用于判断返回的函数是否已经执行。onceConsole等价于:letonceConsole=function(){if(flag){(function(){console.log('onlyprintonce');})()flag=false;}}这也是柯里化函数的简单应用。一个通用柯里化函数的实现既然柯里化函数这么实用,我们能不能实现一个通用柯里化函数呢?所谓通用,就是函数可以将函数参数转换成柯里化函数。看一下第一个版本中实现的代码://firstversionvarcurry=function(fn){varargs=[].slice.call(arguments,1);returnfunction(){varnewArgs=args.concat([].slice.call(arguments));返回fn.apply(null,newArgs);};};函数添加(a,b){返回a+b;}varaddFun=curry(add,1,2);addFun()//3//或varaddOne=curry(add,1);如上面的代码,我们接受一个函数作为参数,然后收集其他的参数,将这些参数传递给这个函数参数来执行。但是上面的代码有个问题,参数不够自由,比如我们要这样调用就会报错:varaddFun=curry(function(a,b,c){returna+b+c;},1);addFun(2)(3);//报错addFun(...)isnotafunction,这似乎违反了我们参数重用的原则,改进如下:functioncurry(fn,args){varlength=fn.length;参数=参数||[];returnfunction(...rest){var_args=[...args,...rest];返回_args.length<长度?curry.call(this,fn,_args):fn.apply(this,_args);}}varfn=curry(function(a,b,c){console.log(a+b+c);});fn('a','b','c');//abcfn('a','b')('c');//abcfn('a')('b')('c');//abc如上完美,这个效用函数的实现可以用一句话来概括:使用闭包来存储函数的参数,当参数达到一定数量时执行函数。PostscriptCurrying基于闭包。不理解闭包可能会阻碍对柯里化的理解。希望这篇文章能帮助你理解和理解Javascript柯里化。能力有限,水平一般。欢迎和赞赏勘误表。订阅更多文章,扫描二维码关注我公众号:回复“666”,即可领取前端技术书籍礼包;
