【.com快译】自2015年以来,随着ECMAScript6(简称ES6)的发布,每年都会发布新版本的ECMAScript规范。每次迭代都会为该语言添加新功能、新语法和新的质量改进。为此,大多数浏览器和Node.js中的JavaScript引擎需要迎头赶上。甚至程序员的编程习惯和代码组织方式也需要与时俱进,以提高整体代码质量,方便后期维护。为了让你更容易写出更简洁、可读性更强的程序代码,本文将在梳理总结ECMAScript最新特性的基础上,为你提供提高JavaScript和Node.js代码质量的七大优秀实践。1.块作用域声明(BlockScopedDeclarations)自语言问世以来,JavaScript开发者一直使用var来声明变量。但是,如以下代码片段所示,使用关键字var创建的变量的作用域存在问题。varx=10if(true){varx=15//innerdeclarationoverridesdeclarationinparentscopeconsole.log(x)//prints15}console.log(x)//prints15由于定义的变量var不是块作用域的,如果在小作用域重新定义in,它们影响外部作用域中的值。但是,如果我们用两个新的关键字let和const替换var,就可以避免这个缺陷(参见下面的代码片段)。lety=10if(true){lety=15//innerdeclarationisscopedwithintheifblockconsole.log(y)//prints15}console.log(y)//prints10当然const和let在语义上是不一样的,那些用const声明的变量,不能重新赋值在其范围内(如下面的代码片段所示)。然而,这并不意味着它们是不可变的,只是它们的引用不能改变。constx=[]x.push("Hello","World!")x//["Hello","World!"]x=[]//TypeError:Attemptedtoassigntoreadonlyproperty。2.箭头函数(ArrowFunctions)作为最近引入JavaScript的一个重要特性,箭头函数有很多优点。首先,它们使JavaScript函数看起来更清晰,更易于开发人员编写。letx=[1,2,3,4]x.map(val=>val*2)//[2,4,6,8]x.filter(val=>val%2==0)//[2,4]x.reduce((acc,val)=>acc+val,0)//10如上例所示,“=>”后面的函数用简洁的语法代替了传统的函数。如果函数体是单个表达式,范围括号{}和return关键字已经隐含了,所以不需要额外写。如果函数只有一个参数,则参数括号()已经隐含了,不需要再写。如果函数体中的表达式是一组字典,则必须用圆括号()括起来。箭头函数的另一个好处是,为了避免使用this关键字带来的不便,箭头函数不定义作用域,而是会存在于它的父作用域中。也就是说,箭头函数对此没有任何绑定。在箭头函数中,this的值与父作用域中的值相同。因此,箭头函数不能用作各种方法或构造函数。它们既不适用于apply、bind或call,也没有super的绑定。此外,箭头函数还有其他限制,例如缺少传统函数可访问的参数对象,以及函数体中缺少yield。可以说,箭头函数并不是标准函数的1:1替代品,而是为JavaScript添加了额外的功能集。3.可选链(OptionalChaining)让我们想象一个类似于人对象的深度嵌套的数据结构。业务应用程序需要访问对象的名字和姓氏。由此,我们可以编写如下JavaScript代码:将出现以下错误。person={age:42}person.name.first//TypeError:Cannotreadproperty'first'ofundefinedperson.name.last//TypeError:Cannotreadproperty'last'ofundefined对于这个,开发者往往需要使用如下代码来解决。显然,这些代码不仅冗长难写,而且可读性也较差。person&&person.name&&person.name.first//undefined而作为JavaScript的一个新特性,可选链的语法允许你访问更深层次的嵌套对象属性,而不必担心该属性是否实际存在。也就是说如果可选链在挖矿过程中遇到null或者undefined值,会通过短路(short-circuit)计算,返回undefined,不会报错。person?.name?.first//undefined如上代码所示,生成的代码简洁明了。4.Null-ish合并在引入null-ish合并运算符之前,JavaScript开发人员需要使用OR运算符--||当输入为空时回退到默认值。这样就会导致即使有合法但错误的值(falsyvalues),也会回落到默认值的情况。functionprint(val){returnval||'Missing'}print(undefined)//'Missing'print(null)//'Missing'print(0)//'Missing'print('')//'Missing'print(false)//'Missing'print(NaN)//'Missing'现在,JavaScript推出了一个空合并运算符--??。它保证仅当前面的表达式为null-ish时才会触发回退。值得注意的是,这里的null值指的是null或者undefined。functionprint(val){returnval??'Missing'}print(undefined)//'Missing'print(null)//'Missing'print(0)//0print('')//''print(false)//falseprint(NaN)//NaN这样,您可以确保您的程序将接受错误值作为合法输入而不会最终被回滚。5.逻辑赋值假设在给变量赋值之前需要先判断是否为空,那么下面的代码展示了基本逻辑:if(x===null||x==undefined){x=y}If如果你熟悉上面提到的短路计算是如何工作的,你可能会使用null-ish合并运算符,用下面更简洁的版本替换上面的三行代码。x??(x=y)//x=yifxisnullish,elsenoeffect从上面的代码可以看出,如果x是null-ish,我们可以使用null-ishmergeoperator的short-circuit函数来执行第二个部分(x=y)。这段代码虽然非常简洁,但不是很容易阅读或理解。我们可以使用以下代码根据逻辑null-ish分配来消除此类变通方法。x??=y//x=yifxisnullish,elsenoeffect类似的,JavaScript也引入了逻辑与赋值--&&=,逻辑或赋值--||=运算符。这些运算符只有在满足某些条件时才被赋值,否则它们没有任何作用。x||=y//x=yifxisfalsy,elsenoeffectx&&=y//x=yifxistruthy,elsenoeffect专家建议:如果你有Ruby编程经验,你会一眼认出||=和&&=运算符。毕竟Ruby没有假值的概念。6、命名捕获组(NamedCaptureGroups)你知道正则表达式中“捕获组”的概念吗?如下代码段所示,是匹配正则表达式括号中部分的字符串。letre=/(\d{4})-(\d{2})-(\d{2})/letresult=re.exec('Pidaythisyearfallson2021-03-14!')result[0]//'2020-03-14',thecompletematchresult[1]//'2020',thefirstcapturegroupresult[2]//'03',thesecondcapturegroupresult[3]//'14',thethirdcapturegroup很长一段时间以来,正则表达式已经可以支持named捕获组。这是一种通过引用名称而不是索引来捕获组的方法。目前,在ES9中,该功能已经由JavaScript实现。如下面的代码片段所示,结果对象包含一个嵌套的组对象,其中每个捕获组的值都可以映射到它的名称。letre=/(?
