ES6 - 迭代器



迭代器介紹

迭代器是一個物件,它允許我們一次訪問一個物件的集合。

以下內建型別預設情況下是可迭代的 -

  • 字串
  • 陣列
  • Map
  • Set

如果一個物件實現了一個鍵為[Symbol.iterator]並返回迭代器的函式,則該物件被認為是可迭代的。可以使用 for...of 迴圈來迭代集合。

示例

以下示例宣告一個數組 marks,並使用for..of迴圈遍歷它。

<script>
   let marks = [10,20,30]
   //check iterable using for..of
   for(let m of marks){
      console.log(m);
   }
</script>

以上程式碼的輸出將如下所示 -

10
20
30

示例

以下示例宣告一個數組 marks 並檢索一個迭代器物件。[Symbol.iterator]()可用於檢索迭代器物件。迭代器的 next() 方法返回一個包含'value''done'屬性的物件。'done' 是布林值,在讀取集合中的所有專案後返回 true。

<script>
   let marks = [10,20,30]
   let iter = marks[Symbol.iterator]();
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
</script>

以上程式碼的輸出將如下所示 -

{value: 10, done: false}
{value: 20, done: false}
{value: 30, done: false}
{value: undefined, done: true}

自定義可迭代物件

JavaScript 中的某些型別是可迭代的(例如 Array、Map 等),而其他型別則不是(例如 Class)。預設情況下不可迭代的 JavaScript 型別可以透過使用可迭代協議進行迭代。

以下示例定義了一個名為CustomerList的類,它將多個客戶物件儲存為一個數組。每個客戶物件都具有 firstName 和 lastName 屬性。

為了使此類可迭代,該類必須實現[Symbol.iterator]()函式。此函式返回一個迭代器物件。迭代器物件有一個函式next,它返回一個物件{value:'customer',done:true/false}

<script>
   //user defined iterable
   class CustomerList {
      constructor(customers){
         //adding customer objects to an array
         this.customers = [].concat(customers)
      }
      //implement iterator function
      [Symbol.iterator](){
         let count=0;
         let customers = this.customers
         return {
            next:function(){
            //retrieving a customer object from the array
               let customerVal = customers[count];
               count+=1;
               if(count<=customers.length){
                  return {
                     value:customerVal,
                     done:false
                  }
               }
               //return true if all customer objects are iterated
               return {done:true}
            }
         }
      }
   }
   //create customer objects
   let c1={
      firstName:'Sachin',
      lastName:'Tendulkar'
   }
   let c2={
      firstName:'Rahul',
      lastName:'Dravid'
   }
   //define a customer array and initialize it let customers=[c1,c2]
   //pass customers to the class' constructor
   let customersObj = new CustomerList(customers);
   //iterating using for..of
   for(let c of customersObj){
      console.log(c)
   }
   //iterating using the next() method
   let iter = customersObj[Symbol.iterator]();
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
</script>

以上程式碼的輸出如下所示 -

{firstName: "Sachin", lastName: "Tendulkar"}
{firstName: "Rahul", lastName: "Dravid"}
{
   done: false
   value: {
      firstName: "Sachin",
      lastName: "Tendulkar"
   }
}
{
   done: false
   value: {
      firstName: "Rahul",
      lastName: "Dravid"
   }
}
{done: true}

生成器

在 ES6 之前,JavaScript 中的函式遵循執行至完成模型。ES6 引入了稱為生成器的函式,這些函式可以在中途停止,然後從停止的地方繼續。

生成器在函式名字首一個星號 * 字元,幷包含一個或多個yield語句。yield關鍵字返回一個迭代器物件。

語法

function * generator_name() {
   yield value1
   ...
   yield valueN
}

示例

該示例定義了一個生成器函式getMarks,其中包含三個 yield 語句。與普通函式不同,生成器函式 getMarks()在呼叫時不會執行函式,而是返回一個迭代器物件,該物件可幫助您執行生成器函式內的程式碼。

在第一次呼叫markIter.next()時,開頭的操作將執行,並且 yield 語句會暫停生成器的執行。後續對markIter.next()的呼叫將恢復生成器函式,直到下一個yield表示式。

<script>
   //define generator function
   function * getMarks(){
      console.log("Step 1")
      yield 10
      console.log("Step 2")
      yield 20
      console.log("Step 3")
      yield 30
      console.log("End of function")
   }
   //return an iterator object
      let markIter = getMarks()
   //invoke statements until first yield
      console.log(markIter.next())
   //resume execution after the last yield until second yield expression
      console.log(markIter.next())
   //resume execution after last yield until third yield expression
      console.log(markIter.next())
      console.log(markIter.next()) // iteration is completed;no value is returned
</script>

以上程式碼的輸出將如下所示 -

Step 1
{value: 10, done: false}
Step 2
{value: 20, done: false}
Step 3
{value: 30, done: false}
End of function
{value: undefined, done: true}

示例

以下示例透過

* evenNumberGenerator 生成器函式建立了一個無限的偶數序列。

我們可以使用next()或使用for of迴圈遍歷所有偶數,如下所示

<script>
   function * evenNumberGenerator(){
      let num = 0;
      while(true){
         num+=2
         yield num
      }
   }
   // display first two elements
   let iter = evenNumberGenerator();
   console.log(iter.next())
   console.log(iter.next())
   //using for of to iterate till 12
   for(let n of evenNumberGenerator()){
      if(n==12)break;
      console.log(n);
   }
</script>

以上程式碼的輸出如下所示 -

{value: 2, done: false}
{value: 4, done: false}
2
4
6
8
10
廣告

© . All rights reserved.