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 await of loop

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

使用 for await of loop 的语法如下,其中,

  • 每次迭代时,都会将不同属性的值分配给 variable,并且可以使用 const、let 或 var 声明变量。

  • iterable −需要迭代其可迭代属性的对象。
for await (variable of iterable) {
    语句
}

示例

以下示例显示了如何使用 for await 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 await 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

Rest/Spread 属性

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

示例:对象和 Rest 运算符

以下示例显示了将 rest 运算符与对象一起使用。student 的 age 属性值被复制到 age 变量中,而其余属性的值则使用 rest 语法 `...` 复制到另一个变量中。

<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得到解决,就会执行 finally(),无论其结果如何。此函数返回一个Promise。它可用于避免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 及更早版本中,如果将无效的转义序列与标记函数一起使用,则会引发语法错误,如下所示 −

//带有无效 unicode 序列的标记函数
myTagFn`\unicode1`
// SyntaxError:格式错误的 Unicode 字符转义序列

但是,与早期版本不同,ES9 将无效的 unicode 序列解析为未定义,并且不会引发错误。这在下面的示例中显示 −

<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,可用于标记函数的第一个参数。此属性允许您访问输入的原始字符串,而无需处理转义序列。

示例

<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"}

正则表达式功能

在正则表达式中,点运算符或句点用于匹配单个字符。. 点运算符 跳过换行符,如 , ,如下例所示 −

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

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

true
false
false

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

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

上述代码的输出将概要 −

true
true

命名捕获组

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

(?<Name1>pattern1)

Example

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