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

90%的前端ES6代码简化技巧,你用过哪些?

时间:2023-03-13 20:33:16 科技观察

前言(ECMAScript简介)JavaScript语言最初有2个标准:ECMA-262:MasterStandard,由ECMA国际组织(EcmaInternational)管理ECMAScript的诞生正好排在Ecma的第262位标准,所以它获得了ECMA-262编号。)ISO/IEC16262:第二个标准,由国际标准组织ISO(InternationalStandardOrganization)和国际电工委员会IEC(InternationalElectrotechnicalCommission)管理,由于商标版权的原因,这种语言在规范标准中被称为ECMAScript,所以原则上JavaScript和ECMAScript指的是同一个东西,但有时也有所区别:语言(标准)历史ECMAScript1(1997年6月):规范第一版ECMAScript2(1998年6月):引入了与ISO标准同步的小更新ECMAScript3(1999年12月):添加了正则表达式、字符串处理、控制语句(do-while、switch)、异常处理(try-catch)和许多其他核心特性ECMAScript4(rpealedinJuly2008):本来是大规模的升级(静态类型、模块、命名空间等),但是跨度太大,有分歧,最终没能推广使用ECMAScript5(2009年12月):变化不大,增加了一些标准库特性和严格模式ECMAScript-5.1(2011年6月):另一个小更新,为了同步ISO标准ECMAScript6(2015年6月):一大波更新,实现了很多愿景当年的ES4,正式改为逐年命名规范版本ECMAScript2016(2016年6月):第一个年度版本,相比ES6,发布周期更短,新特性相对较少ECMAScript2017(6月)2017):第二个年度版本...后续的ECMAScript版本(ES2018,ES2019,ES2020等)6月正式发布批准生效(重点关注ES6)这里总结一下阮一峰先生对ES6标准的介绍:ES6不仅是一个历史名词,而且也是一个统称,意思是5.1版本之后的下一代JavaScriptStandards,涵盖ES2015、ES2016、ES2017等,ES2015是正式名称,特指当年发布的语言标准的正式版本。市面上所说的ES6一般是指ES2015标准,但有时也指代JavaScript的下一代。解释以下内容:块作用域(ES2015)解构(ES2015)ArrowFunctions(ES2015)模板字符串(templatestring,ES2015)Restandspreadparameters(ES2015)对象字面量速记语法(Objectshorthand,ES2015)includes()ofarrayinstances(ES2016)Async/await异步语法(ES2017)为什么块级作用域需要块级作用域?ES5只有globalscope和functionscope,没有Block-levelscope,这让很多场景变得不合理。在第一种情况下,内部变量可能会覆盖外部变量。vartmp=newDate()functionfn(){console.log(tmp)if(false){vartmp=helloworld}}fn()//undefinedcopycode上面代码的原意是if代码块外面使用外部tmp变量,在内部使用内部tmp变量。但是函数fn执行后,输出结果是undefined,因为变量提升导致内层tmp变量覆盖了外层tmp变量。在第二种情况下,用于计数的循环变量作为全局变量泄漏。vars=hellofor(vari=O;i{console.log(i)},1000)}//55555复制代码改成letfor(inES6leti=0;i<5;i++){setTimeout(()=>{console.log(i)},1000)}//01234复制代码看到这里,相信聪明的你明白其中的好处块级作用域O(∩_∩)O那么ES5能不能达到块级作用域的效果呢?是的,我们可以使用闭包for(vari=0;i<5;i++){;(function(index){setTimeout(()=>{console.log(index)},1000)})(i)}//01234复制代码解构解构:是将数据结构分解成更小部分的过程。在ES6中,从数组和对象中提取值,并为变量赋值。那么解构有什么用呢?可以大大简化变量声明操作。//ES5varfoo=1varbar=2varbaz=3//ES6let[foo,bar,baz]=[1,2,3]复制代码2.变量交换:看起来像镜像。赋值语句左侧的解构模式,右侧临时创建的数组文字。x被赋值为数组中y的值,y被赋值为数组中x的值。letx=1lety=2;[x,y]=[y,x]//x=2,y=1复制代码3.对象解构varobj={x:1,y:2,c:1}let{x,y}=obj//x=1//y=2复制代码4.字符串解构const[a,b,c,d,e]=hello//a=>h//b=>e//c=>l//d=>l//e=>o复制代码5.函数参数解构constxueyue={name:Xueyue,age:18,}functiongetAge({name,age}){return`${name}今年${age}yearsold`}getAge(xueyue)//雪月今年18岁复制代码箭头函数ES6允许使用箭头=>definefunctionvarf=v=>v//等价于ES5的varf=function(v){returnv}复制代码如果箭头函数不需要参数或者需要多个参数,参数部分用括号表示。varf=()=>5//相当于ES5的varf=function(){return5}varsum=(numl,num2)=>numl+num2//相当于ES5的varsum=function(numl,num2){returnnuml+num2}Copycode箭头函数可以与解构相结合。constfull=({first,last})=>first++last;//相当于ES5的functionalfull(person){returnperson.first++person.last;}复制代码箭头函数让表达式更简洁constisEven=n=>n%2===0constsquare=n=>n*nvarresult=values.sort((a,b)=>a-b)//相当于ES5的varresult=values.sort(function(a,b){returna-b})复制代码上面的代码只用了两行就定义了两个简单的实用函数。如果不使用箭头函数,可能会占用多行,也没有现在这么醒目。使用箭头函数的注意点函数体中的this对象是定义所在的对象,而不是使用所在的对象。不能作为构造函数使用,即不能使用new命令,否则会抛出错误。arguments对象不能使用,它不存在于函数体内。如果要使用它,可以使用rest参数代替。不能使用yield命令,因此箭头函数不能用作Generator函数。在以上四点中,第一点尤为值得注意。this指向的对象是可变的,但在箭头函数中,它是固定的。//ES6functionfoo(){setTimeout(()=>{console.log(id:,this.id)},100)}//转换为ES5functionfoo(){var_this=thissetTimeout(function(){console.log(id:,_this.id)},100)}复制代码在上面的代码中,转换后的ES5版本清楚地表明箭头函数根本没有自己的this,而是引用了外层的this。模板字符串模板字符串(templatestring)是字符串的增强版本,由反引号(``)标识。它可以作为一个普通的字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。const{log}=consoleconstname=雪月constage=18//普通字符串拼接constresult=name+thisyear+age+age//模板字符串constresult2=`${name}今年${age}`log(result)//雪月今年18岁log(result2)//雪月今年18岁//${}花括号可以放入任何JavaScript表达式,可以计算constresult3=`${name}今年${age*2}Yearsold`log(result3)//雪月今年36岁。复制代码Remainingparameters/ExpansionsyntaxES6引入了restparameters(以...变量名的形式)来获取函数的冗余参数,这样就不需要再使用arguments对象了。带有剩余参数的变量是一个数组,变量将额外的参数放入其中。functionsortNumbers(){returnArray.prototype.slice.call(arguments).sort()}//使用restconstsortNumbers=(...numbers)=>numbers.sort()复制代码比较上面两种写法,我们可以发现rest参数的写法更加自然简洁。展开运算符(spread)是三个点(...)作为rest参数的逆运算,将数组转换为逗号分隔的参数序列console.log(...[1,2,3])//123console.log(1,...[2,3,4],5)//12345CopyCode以下是展开运算符替换apply方法的实际示例应用Math.max方法简化查找最大元素数组。//ESS写法Math.max.apply(null,[14,3,77])//ES6写法Math.max(...[14,3,77])//等价于Math.max(14,3,77)复制代码展开运算符提供了一种新的数组写入方式。//ESS;[1,2].concat(more)//ES6;[1,2,...more]复制代码对象的扩展操作符(...)用于提取所有可遍历的属性参数对象,复制到当前对象。letz={a:3,b:bb}letn={...z}n//{a:3,b:bb}n===z//复制代码特别注意:...扩展对象,只有当对象属性是基本数据类型时才可以做,也就是深拷贝。如果是引用数据类型,就是浅拷贝。letz={a:3,b:bb,c:{name:ccc}}letn={...z}n//{a:3,b:bb,c:{name:ccc}}n===z//falsen.c===z.c//true//n.c和z.c是同一个引用地址复制代码对象字面量简写语法constname=雪月//ES5记法constobj={name:name,f:function(){console.log(this.name)},}//ES6缩写constobj2={name,f(){console.log(this.name)},}obj.f()//雪月obj2.f()//Xueyuecopycode使用vue的同学是不是觉得很熟悉newVue({el:#app,data(){return{list:[],}},})copycode数组实例includes()Array.prototype.includes方法返回一个布尔值,指示数组是否包含给定值,类似于字符串的includes方法。ES2016引入了这个方法。;[1,2,3].includes(2)//true;[1,2,3].includes(4)//false;[1,2,NaN].includes(NaN)//true在此之前方法,我们通常使用数组的indexOf方法来检查它是否包含某个值。//ES5if(arr.indexOf(el)!==-1){//...}//ES6if(arr.includes(el)){//...}//indexOf可以类似吗includes的措辞?我们可以使用~位运算符if(~arr.indexOf(el)){//...}来复制代码indexOf方法有两个缺点,一个不够语义,它的意思是找到第一个参数值位置出现了,所以比较不等于-1不够直观。二是它内部使用了严格的相等运算符(===)进行判断,会导致对NaN的误判。;[NaN].indexOf(NaN)//-1copycodeincludes使用了不同的判断算法,所以不存在这个问题;[NaN].includes(NaN)//真正的copycodeAsync/await异步语法ES2017标准的async函数的引入是为了让异步操作更加方便。什么是异步函数?总之就是Generator函数的语法糖。asyncfunctiongetTitle(url){letresponse=awaitfetch(url)lethtml=awaitresponse.text()returnhtml.match(/([sS]+)/i)[1]}getTitle(https://tc39.github.io/ecma262/).then((res)=>console.log(res))复制代码上面代码中,函数getTitle内部有3个操作:抓取网页,提取文本,匹配页面标题。只有这三个操作都完成了,then方法中的console.log才会被执行。详细看老师的ES6入门教程。如果您认可本书,也可以到正版渠道购买书籍。这样出版商就不会因出版开源图书而亏本,进而鼓励更多的作者将自己的图书开源。后记(ListingAPIs)ES6实用的API还是很多的,我就简单提一下,朋友们看看有没有用;[1,4,-5,10].find(n=>n<0)//-5;[1,5,10,15].findIndex((value,index,arr)=>value>9)//2;[1,2,[3,[4,5]]].flat()//[1,2,3,[4,5]];[1,2,[3,[4,5]]].flat(2)//[1,2,3,4,5];[3,8,54,8,3,NaN,NaN,NaN,NaN].filter((数字,索引,arr)=>arr.indexOf(number)===index)//[3,8,54,"NaN"]使用filter过滤掉重复的,注意缺失NaN;[1,2,3,4.map((item)=>item*2)//[2,4,6,8]在不改变原数组的情况下使用map返回一个新数组//使用reduce求和;减少非常强大!yyds;[0,1,2,3,4].reduce(function(accumulator,currentValue,currentIndex,array){returnaccumulator+currentValue;});//10//ES2017引入了Object.values和Object.entries与Object.keys匹配,作为遍历对象的辅助手段,//for...of循环使用。let{keys,values,entries}=Object;letobj={a:1,b:2,c:3};for(letkeyofkeys(obj)){console.log(key);//a,b,c}for(letvalueofvalues(obj)){console.log(value);//1,2,3}for(let[key,value]ofentries(obj)){console.log([key,value]);//[a,1],[b,2],[c,3]}复制代码