ES2022(ES13)干净代码中的11个惊人的新JavaScript特性。让我们探索ECMAScript2022(ES13)中添加的最新功能并查看它们的用法示例,以便我们更好地理解它们。1.类字段声明在ES13之前,类字段只能在构造函数中声明,不像很多其他语言,我们不能在类的最外层范围内声明或定义它们。汽车类{构造函数(){this.color='blue';这个年龄=2;}}constcar=newCar();console.log(car.color);//blueconsole.log(car.age);//2ES13取消了这个限制,现在我们可以这样写代码了:classCar{color='blue';age=2;}constcar=newCar();console.log(car.color);//blueconsole.log(car.age);//22.私有方法和字段以前,私有成员不能在类中声明。成员通常以下划线(_)为前缀,表示它是私有的,但仍然可以从类和Revise外部访问。类人{_firstName='约瑟夫';_lastName='史蒂文斯';getname(){return`${this._firstName}${this._lastName}`;}}constperson=newPerson();console.log(person.name);//JosephStevens//仍然可以从类外部访问//打算私有的成员console.log(person._firstName);//Josephconsole.log(person._lastName);//Stevens//也可以修改person._firstName='Robert';person._lastName='Becker';console.log(person.name);//RobertBecker使用ES13,我们现在可以向类添加私有字段和成员,方法前面有井号(#),试图从类外访问它们会导致错误:classPerson{#firstName='约瑟夫';#lastName='史蒂文斯';getname(){return`${this.#firstName}${this.#lastName}`;}}constperson=newPerson();console.log(person.name);//SyntaxError:Privatefield'#firstName'mustbe//declaredinananenclosingclassconsole.日志(人。#firstName);console.log(人。#lastName);请注意,这里抛出的错误是语法错误并且发生在编译时,因此您的代码没有任何部分运行,并且编译器甚至不希望您尝试从类中获取外部访问私有字段,因此它假设您'正在尝试声明一个。3.await运算符在JavaScript中,await运算符用于暂停执行,直到Promise被解决(完成或拒绝)。以前,我们只能在异步函数中使用此运算符-使用async关键字声明的函数。我们不能在全球范围内这样做。functionsetTimeoutAsync(timeout){returnnewPromise((resolve)=>{setTimeout(()=>{resolve();},timeout);});}//SyntaxError:awaitisonlyvalidinasyncfunctionawaitsetTimeoutAsync(3000);使用ES13,现在我们可以:functionsetTimeoutAsync(timeout){returnnewPromise((resolve)=>{setTimeout(()=>{resolve();},timeout);});}//等待超时-否抛出错误awaitsetTimeoutAsync(3000);4.静态类字段和静态私有方法我们现在可以在ES13中为类声明静态字段和静态私有方法,静态方法可以使用this关键字访问类中的其他私有/公共静态成员,实例方法可以使用this访问它们。构造函数。类人{静态#count=0;staticgetCount(){返回这个。#count;}constructor(){this.constructor.#incrementCount();}static#incrementCount(){这个。#count++;}}constperson1=newPerson();constperson2=newPerson();console.log(Person.getCount());//25.类静态块ES13允许定义一个在创建类时只执行一次的静态块,类似于C#、Java等支持面向对象编程的语言中的其他Static构造函数。一个类的类主体中可以有任意数量的static{}初始化块,它们将按照与任何交错的静态字段初始化器一起声明的顺序执行,我们可以在静态块中使用超属性来访问超类属性。classVehicle{staticdefaultColor='blue';}classCarextendsVehicle{staticcolors=[];static{this.colors.push(super.defaultColor,'red');}static{this.colors.push('green');}}console.log(Car.colors);//['blue','red','green']6.私有域中的人体工程学品牌检查我们可以使用这个新功能来检查对象是否有特定的私有字段,使用in运算符。类汽车{#color;hasColor(){在此返回#color;}}constcar=newCar();console.log(car.hasColor());//真的;in运算符可以正确区分不同类的同名私有字段:classCar{#color;hasColor(){在此返回#color;}}classHouse{#color;hasColor(){在此返回#color;}}constcar=newCar();consthouse=newHouse();console.log(car.hasColor());//true;console.log(car.hasColor.call(house));//falseconsole.log(house.hasColor());//trueconsole.log(house.hasColor.call(car));//false7,at()方法进行索引我们在JavaScript中通常使用方括号([])来访问数组的第N个元素,通常是一个简单的,我们只访问数组的N-1个属性。constarr=['a','b','c','d'];控制台日志(arr[1]);//b但是,如果我们想使用方括号访问数组末尾的第N项,我们必须使用arr.length-N索引。constarr=['a','b','c','d'];//来自endconsole.log(arr[arr.length-1])的第一个元素;//d//来自endconsole.log的第二个元素(arr[arr.length-2]);//c的新at()方法让我们可以更简洁、更明确地做到这一点,要访问数组末尾的第N个元素,我们只需将一个负值-N传递给at()即可。constarr=['a','b','c','d'];//来自endconsole.log(arr.at(-1))的第一个元素;//d//来自终端控制台的第二个元素.log(arr.at(-2));//除了数组,string和TypedArray对象现在也有at()方法。conststr='代码之美';控制台日志(str.at(-1));//yconsole.log(str.at(-2));//tconsttypedArray=newUint8Array([16,32,48,64]);console.log(typedArray.at(-1));//64console.log(typedArray.at(-2));//488.RegExp匹配索引这个新特性允许我们指定我们要获取的RegExp对象在给定字符串中匹配的开始和结束索引。以前,我们只能获取字符串中正则表达式匹配的起始索引。conststr='sunandmoon';constregex=/and/;constmatchObj=regex.exec(str);//['and',index:4,input:'sunandmoon',groups:undefined]console.log(匹配对象);我们现在可以指定一个d正则表达式标志来获取匹配开始和结束的两个索引。conststr='太阳和月亮';const正则表达式=/and/d;constmatchObj=regex.exec(str);/**['and',index:4,input:'sunandmoon',groups:undefined,indices:[[4,7],groups:undefined]]*/console.log(matchObj);设置了d标志后,返回的对象将具有包含开始和结束索引的indices属性。9.Object.hasOwn()方法在JavaScript中,我们可以使用Object.prototype.hasOwnProperty()方法来检查对象是否具有给定的属性。汽车类{color='green';age=2;}constcar=newCar();console.log(car.hasOwnProperty('age'));//trueconsole.log(car.hasOwnProperty('name'));//false但是,这种方法存在某些问题。一方面,Object.prototype.hasOwnProperty()方法不受保护-它可以通过为类定义自定义hasOwnProperty()方法来覆盖,它可能具有相同的Object.prototype.hasOwnProperty()行为完全不同。汽车类{color='green';年龄=2;//此方法不会告诉我们//此类的对象是否具有给定属性。hasOwnProperty(){返回假;}}constcar=newCar();console.log(car.hasOwnProperty('age'));//falseconsole.log(car.hasOwnProperty('name'));//false另一个问题是,对于使用null原型创建的对象(使用Object.create(null)),尝试对其调用此方法会导致错误。constobj=Object.create(null);obj.color='绿色';obj.age=2;//类型错误:obj.hasOwnProperty不是函数console.log(obj.hasOwnProperty('color'));解决这些问题的一种方法是在Object.prototype.hasOwnProperty函数属性上使用call()方法,如下所示:constobj=Object.create(null);obj.color='绿色';obj.age=2;obj.hasOwnProperty=()=>false;console.log(Object.prototype.hasOwnProperty.call(obj,'color'));//trueconsole.log(Object.prototype.hasOwnProperty.call(obj,'name'));//false这不是很方便,我们可以写一个可重用的函数来避免重复自己:null);obj.color='green';obj.age=2;obj.hasOwnProperty=()=>false;console.log(objHasOwnProp(obj,'color'));//trueconsole.log(objHasOwnProp(obj,'name'));//false但不是必需的,因为我们可以使用新的内置Object.hasOwn()方法。就像我们的可重用函数一样,它接受一个对象和一个属性作为参数,如果指定的属性是对象的直接属性,则返回true。否则,它返回false。常量对象=对象。创建(空);对象。颜色='绿色';对象。年龄=2;对象。hasOwnProperty=()=>false;安慰。日志(Object.hasOwn(obj,'color'));//trueconsole.log(Object.hasOwn(obj,'name'));//false10,errorcause错误对象现在有一个cause属性,它指定导致错误被抛出的原始错误。这有助于向错误添加额外的上下文信息并帮助诊断意外行为,我们可以通过在作为第二个参数传递给Error()构造函数的对象上设置cause属性来指定错误的原因。函数userAction(){尝试{apiCallThatCanThrow();}catch(err){thrownewError('新错误信息',{cause:err});}}try{userAction();}catch(err){console.日志(错误);console.log(`Causeby:${err.cause}`);}11.从最后一个数组中查找在JavaScript中,我们已经可以使用Array的find()方法在数组中查找并通过指定的测试条件元素,同样,我们可以使用findIndex()来查找此类元素的索引。尽管find()和findIndex()都从数组的第一个元素开始搜索,但在某些情况下最好从最后一个元素开始搜索。在某些情况下,我们知道从最后一个元素开始查找可能会提供更好的性能。例如,这里我们试图获取数组中valueprop等于y的项目。使用find()和findIndex():constletters=[{value:'v'},{value:'w'},{value:'x'},{value:'y'},{value:'z'},];constfound=字母。find((item)=>item.value==='y');constfoundIndex=字母。findIndex((item)=>item.value==='y');console.log(found);//{值:'y'}console.log(foundIndex);//3这样可以,但是由于目标对象更接近数组的末尾,如果我们使用findLast()和findLastIndex()方法从数组的末尾开始搜索,我们可以让这个程序运行得更快。constletters=[{value:'v'},{value:'w'},{value:'x'},{value:'y'},{value:'z'},];constfound=letters.findLast((item)=>item.value==='y');constfoundIndex=letters.findLastIndex((item)=>item.value==='y');控制台日志(找到);//{value:'y'}console.log(foundIndex);//3另一个用例可能需要我们专门从数组末尾搜索正确的项目。例如,如果我们想在数字列表中找到最后一个偶数,find()和findIndex()会产生错误的结果:constnums=[7,14,3,8,10,9];//给出14,而不是10constlastEven=nums.find((value)=>value%2===0);//给出1,而不是4constlastEvenIndex=nums.findIndex((value)=>value%2===0);控制台日志(lastEven);//14console.log(lastEvenIndex);//1我们可以在调用find()和findIndex()之前调用数组的reverse()方法来反转元素的顺序。但是这种方法会导致不必要的数组突变,因为reverse()会反转数组的元素。避免这种突变的唯一方法是制作整个数组的新副本,这可能会导致大型数组出现性能问题。此外,findIndex()仍然不适用于反转数组,因为反转元素也意味着更改它们在原始数组中的索引。要得到原始索引,我们需要进行额外的计算,这意味着要编写更多的代码。constnums=[7,14,3,8,10,9];//在//调用reverse()之前使用传播语法复制整个数组constreversed=[...nums].reverse();//正确给出10constlastEven=reversed.find((value)=>value%2===0);//给出1,而不是4constreversedIndex=reversed.findIndex((value)=>value%2===0);//需要重新计算得到原始索引constlastEvenIndex=reversed.length-1-reversedIndex;console.log(lastEven);//10console.log(reversedIndex);//1console.log(lastEvenIndex);//4这就是findLast()和findLastIndex()方法派上用场的地方。constnums=[7,14,3,8,10,9];constlastEven=nums.findLast((num)=>num%2===0);constlastEvenIndex=nums.findLastIndex((num)=>num%2===0);console.log(lastEven);//10console.log(lastEvenIndex);//4这段代码更短,更易读。最重要的是,它会产生正确的结果。结论我们已经看到了ES13为JavaScript带来的最新特性,使用它们来提高我们作为开发人员的生产力,并以更简洁明了的方式编写更清晰的代码。如果你觉得我的文章对你有用,记得点赞,关注我,分享给你的朋友,说不定能帮到他。最后,感谢您的阅读。
