ES9 - 新特性


下面,我们就来了解一下ES9的新特性。让我们首先了解异步生成器。

异步生成器和迭代

可以使用async关键字使异步生成器异步。下面给出了定义异步生成器的语法-

async function* generator_name() {
   //statements
}

例子

以下示例显示了一个异步生成器,它在每次调用生成器的next()方法时返回 Promise。

<script>
   async function* load(){
      yield await Promise.resolve(1);
      yield await Promise.resolve(2);
      yield await Promise.resolve(3);
   }
   
   let l = load();
   l.next().then(r=>console.log(r))
   l.next().then(r=>console.log(r))
   l.next().then(r=>console.log(r))
   l.next().then(r=>console.log(r))
</script>

上述代码的输出如下 -

{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
{value: undefined, done: true}

for 循环的等待

异步可迭代对象无法使用传统的for..of 循环语法进行迭代,因为它们返回 Promise。ES9引入了for循环的await来支持异步迭代

下面给出了使用for wait of 循环的语法,其中,

  • 在每次迭代中,不同属性的值被分配给变量,并且可以使用 const、let 或 var 声明变量。

  • iterable - 要迭代其可迭代属性的对象。
for await (variable of iterable) {
   statement
}

例子

以下示例展示了使用 for wait of 循环来迭代异步生成器。

<script>
   async function* load(){
      yield await Promise.resolve(1);
      yield await Promise.resolve(2);
      yield await Promise.resolve(3);
   }

   async function test(){
      for await (const val of load()){
         console.log(val)
      }
   }
   test();
   console.log('end of script')
</script>

上述代码的输出如下所示 -

end of script
1
2
3

例子

以下示例使用 for wait of 循环迭代数组。

<script>
   async function fntest(){
      for await (const val of [10,20,30,40]){
         console.log(val)
      }
   }
   fntest();
   console.log('end of script')
</script>

上述代码的输出如下 -

end of script
10
20
30
40

静止/扩散特性

ES9 支持将 Rest 和 Spread 运算符与对象一起使用。

示例:对象和剩余运算符

以下示例显示了对对象使用剩余运算符。学生的年龄属性值被复制到年龄变量中,而其余属性的值则使用其余语法“...”复制到另一个变量中。

<script>
   const student = {
      age:10,
      height:5,
      weight:50
   }
   const {age,...other} = student;
   console.log(age)
   console.log(other)
</script>

上述代码的输出如下 -

10
{height: 5, weight: 50}

示例:对象和展开运算符

扩展运算符可用于组合多个对象或克隆对象。这如以下示例所示 -

<script>
   //spread operator
   const obj1 = {a:10,b:20}
   const obj2={c:30}
   //clone obj1
   const clone_obj={...obj1}
   //combine obj1 and obj2
   const obj3 = {...obj1,...obj2}
   console.log(clone_obj)
   console.log(obj3)
</script>

上述代码的输出如下 -

{a: 10, b: 20}
{a: 10, b: 20, c: 30}

承诺:最后()

无论结果如何,只要 Promise 得到解决,finally() 就会被执行该函数返回一个承诺。它可用于避免 Promise 的then()catch()处理程序中的代码重复。

句法

下面提到的语法适用于函数finally()

promise.finally(function() {
});
promise.finally(()=> {
});

例子

以下示例声明一个异步函数,该函数在延迟 3 秒后返回正数的平方。如果传递负数,该函数将引发错误。无论 Promise 被拒绝还是被解决,finally 块中的语句在任何一种情况下都会执行。

<script>
   let asyncSquareFn = function(n1){
      return new Promise((resolve,reject)=>{
         setTimeout(()=>{
            if(n1>=0){
               resolve(n1*n1)
            }
            else reject('NOT_POSITIVE_NO')
         },3000)
      })
   }
   console.log('Start')

   asyncSquareFn(10)//modify to add -10
   .then(result=>{
      console.log("result is",result)
   }).catch(error=>console.log(error))
   .finally(() =>{
      console.log("inside finally")
      console.log("executes all the time")
   })

   console.log("End");
</script>

上述代码的输出将如下所示

Start
End
//after 3 seconds
result is 100
inside finally
executes all the time

模板文字修改

从 ES7 开始,标记模板符合以下转义序列的规则 -

  • Unicode 转义序列使用"\u"表示,例如\u2764\uFE0F

  • Unicode 代码点转义序列使用"\u{}"表示,例如\u{2F}

  • 十六进制转义序列使用"\x"表示,例如\xA8

  • 八进制文字转义序列使用“”表示,后跟一位或多位数字,例如\125

在 ES2016 及更早版本中,如果标记函数使用无效的转义序列,则会抛出语法错误,如下所示 -

//tagged function with an invalid unicode sequence
myTagFn`\unicode1`
// SyntaxError: malformed Unicode character escape sequence

然而,与早期版本不同的是,ES9 将无效的 unicode 序列解析为 undefined 并且不会抛出错误。这如以下示例所示 -

<script>
   function myTagFn(str) {
      return { "parsed": str[0] }
   }
   let result1 =myTagFn`\unicode1` //invalid unicode character
   console.log(result1)
   let result2 =myTagFn`\u2764\uFE0F`//valid unicode
   console.log(result2)
</script>

上述代码的输出如下所示 -

{parsed: undefined}
{parsed: "❤️"}

原始字符串

ES9 引入了一个特殊的属性raw,可在 tag 函数的第一个参数上使用。此属性允许您访问输入的原始字符串,而无需处理转义序列。

例子

<script>
   function myTagFn(str) {
      return { "Parsed": str[0], "Raw": str.raw[0] }
   }
   let result1 =myTagFn`\unicode`
   console.log(result1)

   let result2 =myTagFn`\u2764\uFE0F`
   console.log(result2)
</script>

上述代码的输出如下 -

{Parsed: undefined, Raw: "\unicode"}
{Parsed: "❤️", Raw: "\u2764\uFE0F"}

正则表达式功能

在正则表达式中,点运算符或句点用于匹配单个字符。的。点运算符会跳过\n、\r等换行符,如下例所示 -

console.log(/Tutorials.Point/.test('Tutorials_Point')); //true
console.log(/Tutorials.Point/.test('Tutorials\nPoint')); //false
console.log(/Tutorials.Point/.test('Tutorials\rPoint')); //false

正则表达式模式表示为 / regular_expression/。test() 方法采用字符串参数并搜索正则表达式模式。在上面的示例中,test() 方法搜索以Tutorials 开头、后跟任何单个字符并以Point 结尾的模式。如果我们在Tutorials 和Point 之间的输入字符串中使用\n\r, test() 方法将返回 false。

true
false
false

ES9 引入了一个新标志 - DotAllFlag (\s),可以与 Regex 一起使用来匹配行终止符和表情符号。这如以下示例所示 -

console.log(/Tutorials.Point/s.test('Tutorials\nPoint'));
console.log(/Tutorials.Point/s.test('Tutorials\rPoint'));

上述代码的输出如下 -

true
true

命名捕获组

在 ES9 之前,捕获组是通过索引访问的。ES9 允许我们为捕获组分配名称。其语法如下 -

(?<Name1>pattern1)

例子

const birthDatePattern = /(?<myYear>[0-9]{4})-(?<myMonth>[0-9]{2})/;
const birthDate = birthDatePattern.exec('1999-04');
console.log(birthDate.groups.myYear);
console.log(birthDate.groups.myMonth);

上述代码的输出如下所示 -

1999
04