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

深入理解ES6的《函数》

时间:2023-04-05 19:35:34 HTML5

默认参数在ES5中,要给一个参数指定一个默认值,只能这样:functionmakeRequst(url,timeout,callback){timeout=timeout||2000;回调=回调||function(){}}但是这样有个问题如果timeout传进来的值是0,它也会被赋值为2000,所以更完整的做法是检测参数类型functionmakeRequst(url,timeout,回调){timeout=(typeoftimeout!=='undefined')?超时:2000;回调=(回调类型!=='未定义')?callback:function(){}}在ES6中,直接functionmakeRequst(url,timeout=2000,callback=function(){}){}可以为任意参数指定默认值。指定默认值参数后,可以继续声明没有默认值的参数functionmakeRequst(url,timeout=2000,callback){}是否使用函数默认值主要看调用函数的实参是否相等toundefinedES5nonstrictmode,functionnamedparameters的变化会反映在argumentsobjectfunctionmixArgs(first,second){console.log(first===arguments[0])//trueconsole.log(second===arguments[1])//truefirst='c'second='d'console.log(first===arguments[0])//trueconsole.log(second===arguments[1])//true}mixArgs('a','b')在严格模式下,无论参数如何变化,arguments对象都不会再变化functionmixArgs(first,second){'usestrict'console.log(first===arguments[0])//trueconsole.log(second===arguments[1])//truefirst='c'second='d'console.log(first===arguments[0])//falseconsole.log(second===arguments[1])//false}mixArgs('a','b')如果使用函数默认值,arguments对象的行为将与ES5在严格模式下要保持一致:arguments对象与命名参数保持分离(注:实际上这种分离特性可以使参数恢复到初始值)functionmixArgs(first,second='b'){console.log(first===arguments[0])//trueconsole.log(second===arguments[1])//falsefirst='c'second='d'console.log(first===arguments[0])//falseconsole.log(second===arguments[1])//false}mixArgs('a')函数的默认值既可以给原值,也可以指定函数,但只有当默认值不传入,可以调用。函数,也就是说默认参数只有在函数被调用的时候才会被求值。将默认值指定为函数。不要忘记括号。如果您忘记了圆括号,您将传入函数的引用而不是函数调用的结果。functiongetValue(value){returnvalue+5}functionadd(first,second=getValue(first)){returnfirst+second}console.log(add(1))//7个函数参数有自己的作用域,暂时死掉zone,它不同于函数体的范围是独立的,也就是说参数的默认值是不可访问的。在函数体中声明的变量处理未命名的参数。在命名参数的函数前添加...三个点表示这是一个不确定的参数functionpick(obj,...keys){letresult=Object.create(null)for(leti=0,len=keys.length;我<伦;i++){result[keys[i]]=object[keys[i]]}returnresult}函数的length属性统计了函数命名参数的个数,参数不固定添加不会影响长度属性的值。每个函数最多只能声明一个不确定参数,并且必须放在所有参数的末尾。对象字面量setter中不能使用不确定参数,因为对象字面量setter的参数有andTherecanonlyaletobj={//UncaughtSyntaxError:Setterfunctionargumentmustnotbearestparametersetname(...value){console.log(value)}}看一个有趣的例子:无论是否使用不确定参数,arguments对象总是包含传递给函数的所有参数。默认参数和可变参数的特性同样适用于Function构造函数varadd=newFunction("first","second=first","returnfirst+second")console。log(add(1))//2varpickFirst=newFunction("...args","re??turnargs[0]")console.log(pickFirst(1,2))//1扩展运算符例如,Math.max接受任意数量的参数,返回最大的一个,但是如果传入数组,只能使用applyconsole.log(Math.max(11,2,3,12,43,904,3543,43))letvalues=[11,2,3,12,43,904,3543,43]console.log(Math.max.apply(Math,values))使用展开运算符变得非常简单letvalues=[11,2,3,12,43,904,3543,43]console.log(Math.max(...values))如果想限制Math.max返回的最小值为0,也可以这样做下面使用letvalues=[-11,-2,-3,-12]console.log(Math.max(...values,0))函数的name属性函数的name属性的值不一定是指同名变量,它只是对函数的附加信息辅助调用,所以name属性的值不能用来获取函数引用){return'angela'},sayName:function(){}}console.log(doSome.name)//doSomeElseconsole.log(person.sayName.name)//sayNameconsole.log(person.firstName.name)//undefinedvardoThing=function(){}console.log(doThing.bind().name)//bounddoThingconsole.log((newFunction()).name)//匿名函数多用途JS中有两种不同的内部方法function:[[Call]]and[[Construct]]当通过new关键字调用函数时,会执行[[Construct]]函数,它负责创建一个新的对象,通常称为实例,然后执行函数体,将this绑定到实例。如果不通过new关键字调用函数,就会执行[[Call]]函数,从而直接执行代码中的函数体。并不是所有的函数都有[[Construct]]方法,所以并不是所有的方法都能被new调用,用[[Construct]]方法的函数统称为构造函数。ES5要通过new关键字判断一个函数是否被调用functionPerson(name){if(thisinstanceofPerson){this.name=name}else{thrownewError('必须传递new关键字才能调用')}}但是上面的方法也不是绝对可靠的,比如下面的调用varperson=newPer就会无效son('angela')varnotAPerson=Person.call(person,'Shing')//这样,函数本身无法区分实例是通过Person.Call、Apply还是newcall获取的。在ES6中可以做如下绝对安全的判断函数Person(name){//或者typeofnew.target===Personif(typeofnew.target!=='undefined'){this.name=name}else{thrownewError('mustbecalledwiththenewkeyword')}}varperson=newPerson('angela')varnotAPerson=Person.call(person,'Shing')//调用[[Construct时抛出错误]]函数的方法,new.target被赋值new操作符的目标,如果调用[[Call]]方法,new.target的值未定义在函数外使用new.target是一个语法错误块-levelfunctionES5严格模式,在代码块内声明函数程序会报错ES6严格模式下,可以在代码块内声明函数,块级函数声明会被提升到代码顶部块,超出这个块级范围,函数将不再存在'usestrict'if(true){console.log(typeofdoSomeThing)//functiondoSomeThing()//------------functiondoSomeThing(){console.log('----------')}}console.log(typeofdoSomeThing)//undefined在ES6非严格模式下,这些函数不再被提升到顶部代码块,但位于封闭函数或全局范围的顶部.log('----------')}}console.log(typeofdoSomeThing)//functionarrowfunction箭头函数与传统函数的区别在于:没有this、super、arguments、new.target的绑定——即this、super、arguments、new.targetinarrowfunctions的值由外围最近的一层非箭头函数决定。不能通过new关键字调用——因为箭头函数没有[[Construct]],没有原型——箭头函数不存在。prototype属性不能改变this的绑定——函数内的this值不能改变。不支持参数对象。函数中的参数只能通过命名参数和不确定参数访问。不支持重复的命名参数。当箭头函数只有一个参数时,可以直接写参数名,后面跟箭头。箭头右侧的表达式将在计算后立即返回。即使没有明确的return语句,如果要传入两个或多个参数,也需要在参数两边加一对括号。如果函数没有参数,同样在声明时写一组没有内容的括号letsum=(num1,num2)=>num1+num2//等价于letsum=function(num1,num2){returnnum1+num2}尾call优化tailcallpointer最重要的是该函数被调用为另一个函数的最后一条语句。事实上,如果满足以下三个条件,尾调用不会访问当前栈帧的变量——函数内部不是闭包,尾调用是最后一条语句尾调用,结果返回为一个函数值。ES6严格模式下,JS引擎会自动优化尾调用函数f(x){returng(x);}functionfactorial(n){if(n<=1){return1}else{//不能优化,返回后必须执行乘法returnn*factorial(n-1)}}functionfactorial(n,p=1){if(n<=1)return1*pelse{letresult=n*p;//优化返回阶乘(n-1,result)}}