当前位置: 首页 > Web前端 > HTML

JavaScript函数柯里化

时间:2023-03-29 11:41:03 HTML

JavaScript函数柯里化1.定义:柯里化(Currying)是将一个接受多个参数的函数转化为一个接受单个参数(原函数的第一个参数)的函数,并返回一个函数的一种技术接受剩余参数并返回结果的新函数。让我用一个简单的例子来解释:functionadd(a,b){returna+b}add(1,2);//3将函数add转换为柯里化函数_add:function_add(a){returnfunction(b){returna+b}}_add(1)(2);//3functionadd和function_add是等价的。_add能够处理add的所有剩余参数,因此柯里化也称为部分求值。其实就是把add函数的a和b参数改成了一个接收a的函数,然后返回一个处理b参数的函数。现在思路应该比较清晰了:只传递一部分参数给函数调用,让它返回一个函数来处理剩下的参数。二、柯里化函数的作用1、参数复用案例:拼接地址按照通用思路拼接一个地址//拼接地址functiongetUrl(protocol,hostname,pathname){return`${protocol}${hostname}${pathname}`;}consturl1=getUrl('https://','www.baidu.com','/hasa');consturl2=getUrl('https://','www.知乎','/saandsa');consturl3=getUrl('https://','www.segmentfault.com','/hasak');console.log(url1,url2,url3)每次调用getUrl参数都要重复传入参数'https://'。curry封装后:functioncurry(protocol){returnfunction(hostname,pathname){return`${protocol}${hostname}${pathname}`;}}consturl_curry=curry('https://');consturl1=url_curry('www.baidu.com','/hasa');consturl2=url_curry('www.zhihu.com','/saandsa');consturl3=url_curry('www.segmentfault.com','/hasak');console.log(url1,url2,url3)显然经过柯里化和封装,后面拼接地址的时候,减少了参数个数,降低了代码重复率。2.提前确认/提前返回案例:兼容IE浏览器事件监听方式(IE已死)传统方式:/**@paramelementObjectDOM元素对象*@paramtypeString事件类型*@paramlistenerFunction事件处理函数*@paramuseCaptureBoolean是否捕获*/varaddEvent=function(element,type,listener,useCapture){if(window.addEventListener){element.addEventListener(type,function(e){listener.call(element,e)},useCapture)}else{element.attachEvent('on'+type,function(e){listener.call(element,e)})}}缺陷是每次绑定一个DOM元素时,都需要要重新判断,其实只要浏览器确认过事件监控网页,就可以知道浏览器需要哪种监控方式。所以我们可以让判断只执行一次。curry封装后:varaddEvent=(function(){if(window.addEventListener){returnfunction(element,type,listener,useCapture){//returnfunctionelement.addEventListener(type,function(){listener.call(element)},useCapture)}}else{returnfunction(element,type,listener){element.attachEvent('on'+type,function(){listener.call(element)})}}})()addEvent(element,"click",listener)立即执行函数,多个事件触发时只触发一次if条件判断。3、延时执行案例:钓鱼统计权重传统方法:letfishWeight=0;constaddWeight=function(weight){fishWeight+=weight;};addWeight(2.3);addWeight(6.5);addWeight(1.2);addWeight(2.5);console.log(fishWeight);每执行一次addWeight方法,就将鱼的重量累加一次。柯里化和打包后:functioncurryWeight(fn){let_fishWeight=[];返回函数(){if(arguments.length===0){returnfn.apply(null,_fishWeight);}else{_fishWeight=_fishWeight.concat([...arguments]);}}}functionaddWeight(){让fishWeight=0;for(leti=0,len=arguments.length;ia-b);}const_addWeight=curryWeight(sortWeight);_addWeight(6.5);_addWeight(1.2);_addWeight(2.3);_addWeight(2.5);console.log(_addWeight())很简单,修改addWeight函数即可。3、柯里化函数的实现Done1:step1:实现一个函数add(1)(2)functionadd(num){letsum=num;returnfunction(num){returnsum+num}}console.log(add(1)(2));step2:实现add(1)(2)(3)怎么样?不能无限嵌套,所以返回一个函数名,判断函数内部是否有参数传递functionadd(num){letsum=num;returnadds=function(num1){if(num1){sum=sum+num1;returnadds}returnsum}}console.log(add(1)(2)(3)());step3:如果实现add(1,2,3)(2,1)(3)(2,1,3)?因为每次调用传递的参数都是变长的。所以不能直接把形参写死。functionadd(){//收集参数letparams=[...arguments];constgetParams=function(){//当传入参数为空时,遍历参数数组求和。如果([...arguments].length===0)returnparams.reduce((pre,next)=>pre+next,0);//收集参数params.push(...arguments);返回获取参数;}//重复调用直到传入参数为空returngetParams;}leta=add(1,2)(2,1)(3)();console.log(a);Done2:functioncurry(){letargs=[...参数];letinner=function(){args.push(...参数);回归内心;}//核心内容:隐式转换,调用内部toStringinner.toString=function(){returnargs.reduce(function(pre,next){returnpre+next;})}returninner;}constresult=curry(1)(2);控制台日志(+结果);关于隐式转换1.在JavaScript中,toString()方法和valueOf()方法都可以重写,如果用于操作JavaScript解析器,会自动调用。所以在curried函数的最后重写toString,收集完所有参数就可以执行了。2.JavaScript隐式调用的帖子4.Currying总结函数的Currying,核心思想是收集参数,需要依赖参数和递归,通过拆分参数调用一个多参数的函数方法。达到减少代码冗余,增加可读性的目的。优点:柯里化后,我们不丢失任何参数:log仍然可以正常调用;我们可以很容易地生成偏函数,比如今天用来生成日志的偏函数;单次入境;易于测试和重用。缺点函数嵌套较多;占用内存,可能导致内存泄漏(因为本质是用闭包实现的);效率低下(因为使用了递归);缓慢的变量访问和可访问性差(因为使用参数);应用场景:减少重复传递一些不会改变的参数;将curried回调参数传递给其他函数。