作为前端切图,越来越觉得离不开功能。一提到JavaScript函数,满脑子都是匿名函数、普通函数、闭包函数、构造函数……然后就是一大堆函数概念。如果你达到了这个水平,那么这个功能对你来说并不难,是一个前端老手了。当我闭上眼睛,不看键盘,用手指在键盘上敲击一个排序功能时,我在想,复习一下功能的基础知识会很有趣。函数的默认参数在ES5中,我们给函数传递参数,然后在函数体中设置默认值,如下。函数a(num,回调){num=num||6回调=回调||function(data){console.log('ES5:',data)}callback(num*num)}a()//ES5:36.不传参输出默认值//也可以用callbacka(10,function(data){console.log(data*10)//1000,传参输出新值})在ES6中,我们使用Newdefaultvalue的写法。functiona(num=6,callback=function(data){console.log('ES6:',data)}){callback(num*num)}a()//ES6:36,不传就输出默认值parametersa(10,function(data){console.log(data*10)//1000,传递参数输出新值})使用ES6默认值的写法可以让函数体内的代码更加简洁优雅。默认值是针对arguments对象的影响我们首先要了解arguments对象是什么?准确的说,它是一个类数组对象,存在于函数内部,与当前函数的所有参数组成一个类数组对象。functiona(num,b){console.log(arguments)//{"0":6,"1":10}console.log(arguments.length)//2}a(6,10)的输出上面的结果看起来很正常,那如果我们加上参数的默认值呢?functiona(num=1,b=1){console.log(arguments)}a()//{}默认值无法被参数识别。a(6,10)//{"0":6,"1":10}我们来看看修改参数默认值对参数的影响。1、在ES5的非严格模式下,初始入参为1,那么可以得到arguments[0](代表第一个参数)等于num,修改num=2后,arguments[0]也可以更新to2.functiona(num){console.log(num===arguments[0])//truenum=2//修改参数的默认值console.log(num===arguments[0])//true}a(1)2.在ES5的非严格模式下,函数中修改默认值后参数不能更新。“使用严格”;//严格模式functiona(num){console.log(num===arguments[0]);//真数=2;console.log(num===arguments[0]);//假}a(1);在ES6环境下,默认值对参数的影响与ES5严格模式相同。默认参数表达式参数不仅可以将默认值设置为字符串、数字、数组或对象,还可以是函数。functionadd(){return10}functiona(num=add()){console.log(num)}a()//10个默认参数的临时死区第1章我们提到了let和const变量的临时死区(TDZ),由于默认参数是参数,所以也存在临时死区。函数作用域是独立的,a函数不能共享b函数的作用域参数。//这是一个默认参数临时死区的例子。a初始化的时候,b还没有声明,所以第一个参数是b的一个临时死区。functionadd(a=b,b){console.log(a+b)}add(undefined,2)//b没有定义未命名参数上面说的参数都是命名参数,未命名参数也是函数传递的常参考中使用。当传入的参数是一个对象,而不是具体的参数名时,就是一个无名参数。functionadd(object){console.log(object.a+object.b)}letobj={a:1,b:2}add(obj)//3个可变参数的使用:use...(展开操作字符)是一个不确定的参数,它代表一个数组。functionadd(...arr){console.log(a+b)}leta=1,b=2add(a,b)//3个不确定参数的使用限制:必须放在所有的最后参数并且不能在对象文字设置器中使用。//错误的写法1functionadd(...arr,c){console.log(a+b)}leta=1,b=2,c=3add(a,b,c)//错误的写法写2letobj={setadd(...arr){}}ES6中的构造函数Function增加了对默认参数和可变参数的支持。展开运算符(...)展开运算符的作用是解构数组,然后将每个数组元素作为函数参数传递。有了展开运算符,我们在操作数组的时候,就可以不用再用apply来指定上下文了。//ES5的写法letarr=[10,20,50,40,30]leta=Math.max.apply(null,arr)console.log(a)//50//ES6的写法letarr=[10,20,50,40,30]leta=Math.max(...arr)console.log(a)//严格模式下的50个块级函数:在ES6中,您可以在块中声明-levelscope函数,该函数的作用域仅限于当前块,块外无法访问。"usestrict";if(true){consta=function(){}}非严格模式:即使在ES6中,非严格模式下块级函数的作用域也会提升到父作用域功能顶层。所以大家在写代码的时候尽量使用严格模式来避免这些奇怪的情况。箭头函数(=>)如果看到你这里,你发现你的项目中没有用过箭头函数,没关系,你的水平不低,只是你学习不够努力。constarr=[5,10]consts=arr.reduce((sum,item)=>sum+item)console.log(s)//15箭头函数和普通函数的区别是:1.箭头函数做没有this,函数内部的this来自父级最近的非箭头函数,并且this的方向不能改变。2.箭头函数没有super3,箭头函数没有arguments4,箭头函数没有new.target绑定。5、new6不能用,没有原型。7.不支持重复的命名参数。箭头函数简单理解1、箭头函数左边代表输入参数,右边代表输出结果。consts=a=>aconsole.log(s(2))//22.在箭头函数中,最重要的这个错误将不再是你每天担心的bug。3.箭头函数也可以输出对象,推荐在react的action中使用。constaction=(type,a)=>({type:"TYPE",a})4.支持立即函数表达式consttest=((id)=>{return{getId(){console.log(id)}}})(18)test.getId()//185.箭头函数对数组进行排序constarr=[10,50,30,40,20]consts=arr.sort((a,b)=>a-b)console.log(s)//[10,20,30,40,50]尾调用优化尾调用是什么鬼?尾调用是指在函数返回时调用新函数。由于尾调用的实现需要保存在内存中,在一个循环体中,如果有函数尾调用,你的内存可能满了或者溢出了。在ES6中,引擎会帮你优化尾调用。不需要自己优化,但是需要满足以下三个要求:1.函数不是闭包。2.尾调用是函数的最后一条语句。3.尾调用的结果作为函数返回满足上述要求的函数如下:"usestrict";functiona(){returnb();}以下是不尽如人意的写法://没有return不优化"usestrict";functiona(){b();}//不是直接返回函数,没有优化"usestrict";functiona(){return1+b();}//尾调用是不是最后语句的函数,不优化"usestrict";functiona(){consts=b();returns}//闭包没有优化"usestrict";functiona(){constnum=1functionb(){returnnum}returnb}真正的尾调用目的——递归函数优化在ES5时代,我们不推荐使用递归,因为递归会影响性能。但是通过尾调用优化,递归函数的性能得到了提升。//新的尾部优化写法“usestrict”;functiona(n,p=1){if(n<=1){return1*p}lets=n*preturna(n-1,s)}//求1x2x3的阶乘letsum=a(3)console.log(sum)//6函数小结本章涉及到很多知识点,默认参数,命名参数,可变参数,扩展操作说明符,箭头函数,尾调用优化。初次学习这方面知识的人可以注意一下箭头函数和展开运算符的使用。这是最重要也是最常用的知识。如果你已经在项目中使用了这些知识,作为加固也是有帮助的。俗话说,前车之鉴。=>返回文章目录
