前端JavaScript彻底弄懂函数柯里化curry_第1页
前端JavaScript彻底弄懂函数柯里化curry_第2页
前端JavaScript彻底弄懂函数柯里化curry_第3页
前端JavaScript彻底弄懂函数柯里化curry_第4页
前端JavaScript彻底弄懂函数柯里化curry_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、前端JavaScript彻底弄懂函数柯化curry录、什么是柯化( curry)、柯化的途三、如何封装柯化具函数、什么是柯化(在数学和计算机科学中,柯化是种将使多个参数的个函数转换成系列使个参数的函数的技术。举例来说,个接收3个参数的普通函数,在进柯化后, 柯化版本的函数接收个参数并返回接收下个参数的函数, 该函数返回个接收第三个参数的函数。最后个函数在接收第三个参数后, 将之前接收到的三个参数应于原普通函数中,并返回最终结果。数学和计算科学中的柯化:/ 数学和计算科学中的柯化:/个接收三个参数的普通函数function sum(a,b,c) console.log(a+b+c)/于将普通函数

2、转化为柯化版本的具函数function curry(fn) /. 内部实现省略,返回个新函数/获取个柯化后的函数let _sum = curry(sum);/返回个接收第个参数的函数let A = _sum(1);/返回个接收第三个参数的函数let B = A(2);/接收到最后个参数,将之前所有的参数应到原函数中,并运B(3)/ print : 6对于Javascript 语来说,我们通常说的柯化函数的概念,与数学和计算机科学中的柯化的概念并不完全样。在数学和计算机科学中的柯化函数,次只能传递个参数;我们Javascript 实际应中的柯化函数,可以传递个或多个参数。来看这个例:/普通函数f

3、unction fn(a,b,c,d,e) console.log(a,b,c,d,e)/成的柯化函数let _fn = curry(fn);_fn(1,2,3,4,5);/ print: 1,2,3,4,5_fn(1)(2)(3,4,5); / print: 1,2,3,4,5_fn(1,2)(3,4)(5); / print: 1,2,3,4,5_fn(1)(2)(3)(4)(5); / print: 1,2,3,4,5对于已经柯化后的 _fn 函数来说,当接收的参数数量与原函数的形参数量相同时,执原函数;当接收的参数数量于原函数的形参数量时,返回个函数于接收剩余的参数,直接收的参数数量与

4、形参数量致,执原函数。当我们知道柯化是什么了的时候,我们来看看柯化到底有什么?、柯化的途柯化实际是把简答的问题复杂化了,但是复杂化的同时,我们在使函数时拥有了更加多的由度。这对于函数参数 的由处理,正是柯化的核所在。柯化本质上是降低通性,提适性。来看个例:我们作中会遇到各种需要通过正则检验的需求,如校验电话号码、校验邮箱、校验份证号、校验密码等,这时我们会 封装个通函数 checkByRegExp ,接收两个参数,校验的正则对象和待校验的字符串function checkByRegExp(regExp,string) return regExp.test(string);checkByRegE

5、xp(/1d10$/,; / 校验电话号码checkByRegExp(/(w)+(.w+)*(w)+(.w+)+)$/, ); / 校验邮箱上这段代码,乍看没什么问题,可以满我们所有通过正则检验的需求。但是我们考虑这样个问题,如果我们需要校 验多个电话号码或者校验多个邮箱呢?我们可能会这样做:checkByRegExp(/1d10$/,; / 校验电话号码checkByRegExp(/1d10$/,; / 校验电话号码checkByRegExp(/1d10$/,; / 校验电话号码check

6、ByRegExp(/(w)+(.w+)*(w)+(.w+)+)$/, ); / 校验邮箱checkByRegExp(/(w)+(.w+)*(w)+(.w+)+)$/, test); / 校验邮箱checkByRegExp(/(w)+(.w+)*(w)+(.w+)+)$/, test); / 校 验 邮 箱我们每次进校验的时候都需要输串正则,再校验同类型的数据时,相同的正则我们需要写多次,这就导致我们在使的时候效率低下,并且由于checkByRegExp 函数本是个具函数并没有任何意义, 段时间后我们重新来看这些代码时,如果没有注释,我们必须通过检查正则的内容, 我们才能知道我们校验的是电话号码

7、还是邮箱,还是别的什么。此时,我们可以借助柯化对checkByRegExp 函数进封装,以简化代码书写,提代码可读性。/进柯化let _check = curry(checkByRegExp);/成具函数,验证电话号码let checkCellPhone = _check(/1d10$/);/成具函数,验证邮箱let checkEmail = _check(/(w)+(.w+)*(w)+(.w+)+)$/);checkCellPhone; / checkCellPhone; / checkCellPhone; / c

8、heckEmail(); / 校验邮箱checkEmail(test); / 校验邮箱checkEmail(test); / 校验邮箱再来看看通过柯化封装后,我们的代码是不是变得简洁直观了呢。经过柯化后,我们成了两个函数checkCellPhone 和 checkEmail , checkCellPhone 函数只能验证传的字符串是否是电话号码, checkEmail 函数只能验证传的字符串是否是邮箱, 它们与 原函数 checkByRegExp 相,从功能上通性降低了,但适性提升了。 柯化的这种途可以被理解为:参数复我们再来看个例假定我们有这样段数据:let list = name:lucy

9、,name:jack我们需要获取数据中的所有 name 属性的值,常规思路下,我们会这样实现:let names = list.map(function(item) return ;)那么我们如何柯化的思维来实现呢let prop = curry(function(key,obj) return objkey;)let names = list.map(prop(name)看到这,可能会有疑问,这么简单的例,仅仅只是为了获取name 的属性值,为何还要实现个prop 函数呢,这样太烦了吧。我们可以换个思路,prop 函数实现次后,以后是可以多次使的,所以我们在考虑代码复杂程度的时候,是可以将p

10、rop 函数的实现去掉的。我们实际的代码可以理解为只有let names = list.map(prop(name)这么看来,通过柯化的式,我们的代码是不是变得更精简了,并且可读性更了呢。三、如何封装柯化具函数接下来,我们来思考如何实现curry 函数。回想之前我们对于柯化的定义,接收部分参数,返回个函数接收剩余参数,接收够参数后,执原函数。 length属性,获取函数的形参个数,形参的个数就是所需的参数个数在调柯化具函数时,动指定所需的参数个数我们将这两点结合以下,实现个简单curry 函数:/*将函数柯化param fn待柯化的原函数param len所需的参数个数,默认为原函数的形参个数

11、*/function curry(fn,len = fn.length) return _curry.call(this,fn,len)/*中转函数param fn待柯化的原函数param len所需的参数个数param args 已接收的参数列表*/function _curry(fn,len,.args) return function (.params) let _args = .args,.params; if(_args.length = len)return fn.apply(this,_args);elsereturn _curry.call(this,fn,len,._args

12、)我们来验证下:let _fn = curry(function(a,b,c,d,e) console.log(a,b,c,d,e);_fn(1,2,3,4,5);/ print: 1,2,3,4,5_fn(1)(2)(3,4,5); / print: 1,2,3,4,5_fn(1,2)(3,4)(5); / print: 1,2,3,4,5_fn(1)(2)(3)(4)(5); / print: 1,2,3,4,5我们常的具库 lodash 也提供了 curry 法,并且增加了常好玩的placeholder 功能,通过占位符的式来改变传参数的顺序。如说,我们传个占位符,本次调传递的参数略过占

13、位符,占位符所在的位置由下次调的参数来填充,如这样: 直接看下官的例:接下来我们来思考,如何实现占位符的功能。lodash 的curry 函数来说,curry lodash lodash 对象当做默认占位符来使。我们的实现的 curry 函数,本并没有挂载在任何对象上,所以将curry 函数当做默认占位符使占位符,的是改变参数传递的顺序,所以在curry 函数实现中,每次需要记录是否使了占位符,并且记录占位符所代表的参数位置。直接上代码:/*param fn待柯化的函数param length需要的参数个数,默认为函数的形参个数param holder占位符,默认当前柯化函数return Fu

14、nction柯化后的函数*/function curry(fn,length = fn.length,holder = curry) return _curry.call(this,fn,length,holder,)/*中转函数param fn柯化的原函数param length原函数需要的参数个数param holder接收的占位符param args已接收的参数列表param holders已接收的占位符位置列表return Function继续柯化的函数 或 最终结果*/function _curry(fn,length,holder,args,holders) return func

15、tion(._args)/ 将参数复制份,避免多次操作同函数导致参数混乱let params = args.slice();/ 将占位符位置列表复制份,新增加的占位符增加此let _holders = holders.slice();/ 循环参,追加参数 或 替换占位符_args.forEach(arg,i)=/ 真实参数 之前存在占位符 将占位符替换为真实参数if (arg != holder & holders.length) let index = holders.shift();_holders.splice(_holders.indexOf(index),1); paramsinde

16、x = arg;/ 真实参数 之前不存在占位符 将参数追加到参数列表中else if(arg != holder & !holders.length) params.push(arg);/ 传的是占位符,之前不存在占位符 记录占位符的位置else if(arg = holder & !holders.length) params.push(arg);_holders.push(params.length - 1);/ 传的是占位符,之前存在占位符 删除原占位符位置else if(arg = holder & holders.length) holders.shift(););/ params

17、中前 length 条记录中不包含占位符,执函数if(params.length = length & params.slice(0,length).every(i=i!=holder) return fn.apply(this,params);elsereturn _curry.call(this,fn,length,holder,params,_holders)验证下:let fn = function(a, b, c, d, e) console.log(a, b, c, d, e);let _ = ; / 定义占位符let _fn = curry(fn,5,_); / 将函数柯化,指定所需的参数个数,指定所需的占位符_fn(1, 2, 3, 4, 5);/ print: 1,2,3,4,5_fn(_, 2, 3, 4, 5

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论