当前位置: 首页 > 科技观察

JavaScript函数实析

时间:2023-03-17 15:25:42 科技观察

JS函数式分析0x00入门介绍(废话)近两年,要说函数式编程不流行,那是不可能的,因为大家都知道函数式编程很流行。为什么函数式编程流行?它的想法非常强大和强大!特别是前端redux在reducer上使用纯函数,函数式风格的好处也逐渐被发掘。作者最近看了一些函数式的东西,现发给大家学习学习,顺便也学习一下写文章的方法。。。:P常用的函数式库:ramda是一个精心设计的库比较常用的库underscore应该是个不错的库0x01纯函数定义:相同的输入一定要得到相同的输出,运行时不要修改。不读取外部环境变量的函数肯定不好理解。您仍然必须查看代码。就像你永远不知道国足为什么会输给月薪一样。几百叙.//Array.slice一定是固定输入有固定输出,而且不依赖于外部变量,什么?是否依赖于arr变量?//其实这种写法和Array.prototype.slice(arr,0,3)是一样的;是一样的。你是这样理解的,//你也学到了Array.slice不会修改原始数组的东西!vararr=[1,2,3,4,5];arr.slice(0,3);//Array.splice会修改xs,所以是不纯的,所以相同的输入不会有相同的输出!varxs.splice(0,3);//=>[1,2,3]xs.splice(0,3);//=>[4,5]xs.splice(0,3);//=>[]纯函数的好处:不修改外部变量不会有线程安全问题,可以大大降低系统的复杂度。柯里化0x02函数!code!//calldoWht('me','home','dinner');letdoWhat=(who,where,what)=>{returnwho+'in'+where+'do'+what}//柯里化后等价//calldoWhat('I')('home')('dinner')letdoWhat=who=>where=>what=>{returnwho+'in'+where+'doing'+what}//现在假设'我'在'home',但是不知道怎么办//tmp函数已经帮我们存好值了,很灵活。letdo什么Curry=doWhat('I')('Home')上面提到的库中有一个叫做curry的函数,它会柯里化一个普通的函数。0x03函数的组合函数是把函数组合在一起生成一个新的函数//h(g(f(x)))varadd1=x=>x+1varmul5=x=>x之前函数是这样调用的*5//compose会生成一个新的函数,将接收到的所有参数传给add1,然后将add1的返回值传给mul5(注意!,mul5的参数个数只能是一个!!!),然后compose生成的新函数的返回值就是mul5.compose的返回值(mul5,add1)(2)函数组合很强大,能通过组合生成新函数很爽。如果灵活使用,会大大减少你的代码量(如果不能减少,不要喷我),compose的实现在上面提到的三个库中都有实现。0x04Declarativeandimperativestyle命令式风格让我们通过代码引导机器,让机器一步步完成我们想要的任务;而statement公式就是直接告诉机器我要做什么,比较直观。//命令式varpersons=[...]for(vari=0;persons.length;++i){persons[i]=persons[i]。toUppercase()}//声明式varpersons=[...]persons.map(person=>person.toUppercase())0x05Pointfreestyle//Assumeifletmap=fn=>list=>list.map(fn);letadd=(a,b)=>a+b;//函数incrementAll不是pointfree风格//因为这里提到了numbers参数,所以需要给个名字。//这样定义函数会导致我们需要再命名一个变量。麻烦!letincrementAll=(numbers)=>map(add(1))(numbers);//Pointfree风格定义方式//假设add已经柯里化了letincrementAll=map(add(1))现在推荐Pointfree风格代码(当定义一个函数),这将减少我们不必要的命名。多用这种风格!0x06容器(Functor)容器代表一个值,一个任意值。它就像一个函数编程中的变量,函数的盔甲。它可以让你的变量和函数在工程的战场上立于不败之地!varContainer=function(x){this.__value=x;}Container.of=x=>newContainer(x);Container.prototype.map=function(f){returnContainer.of(f(this.__value))}Container.of(3).map(x=>x+1).map(x=>x*5)//of用于构建容器,map用于转换容器。//Functor可以做很多事情,具体是?下面介绍一下。//也许是在普通容器上检查空值的新行为。varMaybe=function(x){this.__value=x;}Maybe.of=function(x){returnnewMaybe(x);}Maybe.prototype.map=function(f){returnthis.isNothing()?Maybe.of(null):Maybe.of(f(this.__value));}Maybe.prototype.isNothing=function(){return(this.__value===null||this.__value===undefined);}//例子,如果name为空,则输出空varfunctor=Maybe.of({name:'mrcode'})functor.map(value=>value.age).map(String.prototype.upperCase).map(value=>console.log(value))这个Maybe有什么用?就是空值检测。看上面的例子。如果不进行null判断,第二个map会调用String.prototype.upperCase函数,会抛出异常。恐怕吧?:P,而且现在很多语言,比如swift,都增加了类似的支持。optionalMaybe只能判断为空,而Either才是真正处理错误的容器。Either有两个子类,Left和Right。//Promise通过catch方法接收错误,如:doSomething().then(async1).then(async2).catch(e=>console.log(e));//一模一样varLeft=function(x){this.__value=x;}varRight=function(x){this.__value=x;}//完全一样Left.of=function(x){returnnewLeft(x);}Right.of=function(x){returnnewRight(x);}//这里不同!!!Left.prototype.map=function(f){returnthis;}Right.prototype.map=function(f){returnRight.of(f(this.__value));}//应用:vargetAge=user=>user.age?Right.of(user.age):Left.of("ERROR!")getAge({name:'stark',age:'21'}).map(age=>'Ageis'+age);//=>Right('Ageis21')getAge({name:'stark'}).map(age=>'Ageis'+age);//=>Left('ERROR!')Left会跳过所有执行过程,直接对结果来说,就好像Right是一个接一个箭头指向流程图中的下一个任务,而Left直??接指向结果,这是一个错误的结果。0x07IO,在函数式编程中,牵扯到IO总是很尴尬的,Lan很瘦。。还好有一个IO处理IO的东西(不要太绕口),看代码,//没有问题varIO=function(f){this.__value=f;}//???不懂,后面再解释。。IO.of=x=>newIO(_=>x);//???Whatisthis?????IO.prototype.map=function(f){returnnewIO(compose(f,this.__value))};权威回答:这里IO中存放了一个function,它包装了外部环境变量。我们传入一个函数,其中包含实际将执行的IO操作的值。我们把不纯的IO操作放在在这个函数中,一般来说,我们的IO对象是不会进行这些不纯操作的。还是纯的,因为IO操作根本不执行内部函数,这个函数是给外部调用者Executed的。也就是说,不纯的操作是外部人做的,跟我们的IO对象没有关系!(干得好!)看一个例子。vario_document=newIO(_=>window.document);io_document.map(function(doc){returndoc.title});//获取IO(documen.title)科普:这里你获取的不是document.title,你获取的只是一个会返回document.title的函数,这个函数是不纯的,但是执行的不是上面的代码,错在调用函数的人身上!上面的代码仍然是“纯”的!0x08Monad看这部分的时候,建议看一下IO的实现,好好理解,我知道有点烧脑,但是看看也无妨!玩过Promise的都知道,传入Promise.then的函数可以返回一个新的Promise。Promise是Monad.0x09函数式编程应用react纯组件//固定输入得到固定输出纯组件大大增加了react的灵活性//app状态交给一些状态机管理如reduxvarText=props=>({props.text}

)reducerinredux//输入当前state和action,输出nowStatereducer(currentState,action)=>newState0x10总结一下,确实是这样,如果不总结,不像一篇文章,总结一下:纯函数的概念和函数柯里化的概念以及函数的组合容器,Container和Maybe,从Either派生的Left,Right和IO的作用。函数式编程的应用参考文章JavaScript函数式编程3