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 迴圈

非同步可迭代物件不能使用傳統的 **for..of 迴圈** 語法進行迭代,因為它們返回 Promise。ES9 引入了 **for await of 迴圈** 來支援 **非同步迭代**。

使用 **for await of 迴圈** 的語法如下所示,其中:

  • 在每次迭代中,一個不同屬性的值被賦值給 **變數**,並且變數可以用 const、let 或 var 宣告。

  • **iterable** - 要迭代其可迭代屬性的物件。
for await (variable of iterable) {
   statement
}

示例

以下示例演示瞭如何使用 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

剩餘/擴充套件屬性

ES9 支援在物件中使用剩餘和擴充套件運算子。

示例:物件和剩餘運算子

以下示例演示瞭如何在物件中使用剩餘運算子。student 的 age 屬性的值被複制到 age 變數中,而其餘屬性的值使用剩餘語法 `...` 複製到 other 變數中。

<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。它可以用於避免在 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**,它在傳遞給標記函式的第一個引數上可用。此屬性允許您訪問原始字串,就像它們輸入時一樣,無需處理轉義序列。

示例

<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
廣告