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

js中的函数式编程

时间:2023-03-27 12:33:30 JavaScript

函数是javascript中非常重要的一部分,它的用途非常多。可以作为参数、返回值、回调等。下面是函数式编程的一些重要概念和定义纯函数纯函数属于编程的名词在其他语言中也存在,但是在javascript中,满足以下条件的函数规则是一个纯函数。该函数具有相同的输入并且必须具有相同的输出。函数的输出只与输入有关,与其他隐藏信息无关。它不能产生任何副作用,例如触发事件和其他副作用:除了返回函数值外,它还会产生其他函数给调用函数。影响,比如修改全局变量,修改参数,或者改变外部存储。下面举几个例子来区分纯函数和非纯函数1.数组方法vararr1=[1,2,3,4]vararr2=[10,20,30,40]constnewArr1=arr1.splice(1,3)constnewArr2=arr2。slice(1,3)控制台。log(arr1,newArr1)//[1][2,3,4]控制台。log(arr2,newArr2)//[10,20,30,40][20,30]splice通过下标值和长度操作原数组本身,修改入参,所以不是纯函数。slice通过下标值截取数组,返回一个新数组,没有副作用,是纯函数。2.修改入参varobj={name:'alice'}functionfoo(info){info.name='kiki'returninfo}foo(obj)functionbar(info){return{...info,name:'kiki'}}bar(obj)上面两个函数的作用是返回一个新的对象,但是foo修改了入参,所以foo不是一个纯函数,bar也不会产生任何副作用,满足纯函数的定义使用纯函数在开发中有一些优势。不需要考虑传入的参数是否发生了变化。不需要考虑函数的运行是否会修改一些全局变量和外部变量。这样一来,函数的功能就更加单一纯粹了,可以放心的写写写了。使用柯里化通过函数返回一个函数,实现多次接收参数并进行统一处理的函数编码形式{returnfunction(b){returnfunction(c){returna+b+c}}}sum(1,2,3)add(1)(2)(3)以上两个函数的执行结果为相同,但调用方法不同。使用柯里化的好处是让每个函数的功能更加单一,逻辑复用functionfoo(type,time,message){console.log(`${type}:${[time]}:${message}`)}foo('error','2021/10/24','接口返回数据异常')foo('error',newDate(),'页面显示错误')//柯里化函数log(type){返回函数(时间){返回函数(消息){console.log(`${type}:${[time]}:${message}`)}}}varerror=log('error')error('2021/10/24')('接口返回数据异常')error(newDate())('页面显示错误')如上柯里化代码,复用了【获取类型】部分函数组合函数组合function不是函数类型,而是创建一个新的函数来组合多个函数的函数functionmul(m){returnm*2}functionsquare(n){returnn*n}//Composefunctionfunctioncompose(m,n){返回函数(i){返回m(n(i))}}varfn=compose(mul,square)console.log(fn(5))通过组合函数,可以使用with语句组合不同函数的函数with语句可以创建一个独立的作用域with语句的语法是with(){},with括号需要要传递一个值,通常是一个对象,with语句中的变量会先从括号中查找varmessage='global'varobj={name:'alice',message:'obj'}functionfoo(){console.log(message)with(obj){console.log(message)}}foo()上面代码的执行结果如下目前不建议使用with语句使用evaleval解析字符串执行代码varstr="varmessage='global';console.log(message)"eval(str)上面代码执行后,控制台会输出global。目前不推荐使用eval。从上面的代码我们可以看出可读性很差。它也不容易维护。eval字符串在执行过程中很可能被篡改,容易受到攻击。js代码在解析过程中可以通过js引擎进行优化。如果是字符串,则没有办法在全局或函数中优化严格模式在严格模式下,使用“usestrict”开启严格模式。在严格模式下,不允许写一些松散的代码,浏览器会对代码进行更严格的检测。严格模式对javascript语义Error]施加了一些限制,以消除一些原始的[silent]错误。Silenterrors:比如定义没有关键字声明的变量,比如num=12,严格模式可以在js引擎执行代码的时候进行更多的优化(不需要特殊的语法处理)比如下面的代码,通过定义name属性为不可修改属性描述符varobj={}Object.defineProperty(obj,"name",{writable:false})obj.name="alice"非严格模式直接赋值被忽略,严格模式会报错3.严格模式禁用了一些可能在未来ECMAScript版本中定义的文法,例如:keywordfunctionvarnewreservedwordclassletconst(ES5之前)reservedwordsmaybeupgratedtokeywords非严格模式以前可以使用保留字作为变量,例如varlet="abc"在严格模式下会报错。具体来说,严格模式有以下限制:1.不能意外创建全局变量。在非严格模式下,没有通过关键字定义的变量会被添加到全局严格模式下这样的代码执行会抛出异常信息未定义message="hello"2.严格模式会导致赋值操作导致silentfailuretothrowanexceptionSilentlyfail:silentlyfail,noerrorreportedandhasnoeffect在非严格模式下不报错,在严格模式下直接抛出异常Cannotcreateproperty'message'onboolean'true'true.name="alice"3、严格模式下,删除不可删除的属性时抛出异常。非严格模式不报错,忽略删除操作,严格模式直接抛异常Cannotdeleteproperty'address'of#varuser={name:'alice'}Object.defineProperty(user,'address',{value:'Shanghai'})删除用户。地址4.严格模式不允许函数参数具有相同的名称。在非严格模式下执行函数,最终输出3,2,3。在严格模式下,抛出异常SyntaxError:Duplicateparameternamenotallowedinthiscontext"usestrict"functionfoo(a,b,a){console.log(a,b,a)}foo(1,2,3)5.不允许0的八进制语法在非严格模式下,以0开头的数字可以表示八进制,在严格模式下,定义一个数字开始with0会抛出异常严格模式下不允许使用八进制文字。严格模式下,可以用其他方式定义基数,比如0o(八进制),0x(十六进制),0b(二进制)varnum=0212console.log(num)6,strict非严格模式下,输出gloabl.在严格模式下,直接抛出异常。严格模式代码可能不包含with语句varmessage='global'varobj={name:'alice'}with(obj){console.log(message)}7.在严格模式下,eval不再引用上层级变量。在非严格模式下,变量定义在eval执行的字符串中,变量会被添加到global中。将被添加。下面的代码会在非严格模式下输出两个global,在严格模式下输出一个global,并抛出异常messageisnotdefinedvarstr="varmessage='global';console.log(message)"eval(str)console.log(message)8.在严格模式下,这个绑定默认不会转换为对象独立函数调用。在非严格模式下,this指向window。在严格模式下,this默认不会指向window。以下代码在非严格模式下输出window对象,在严格模式下输出undefinedfunctionfoo(){console.log(this)}foo()以上纯函数、柯里化、复合函数、with语句、eval、严格模式它们都是函数式编程中的概念。关于高级js,开发者需要掌握的东西还是很多的。可以看看我写的其他博文,持续更新中~