Es6-iterator

提供:Dev Guides
移動先:案内検索

ES6-イテレーター

イテレーターの紹介

イテレータは、オブジェクトのコレクションに一度に1つずつアクセスできるようにするオブジェクトです。

次の組み込み型はデフォルトで反復可能です-

  • ひも
  • アレイ
  • Map
  • Set

キーが [Symbol.iterator] である関数を実装し、イテレーターを返す場合、オブジェクトは*反復可能*と見なされます。 for …​ ofループを使用して、コレクションを反復できます。

次の例では、 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

次の例では、配列を宣言し、イテレータオブジェクトをマークして取得します。 * [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の特定のタイプは反復可能です(例: 配列、マップなど)が他の場合はありません(例: クラス)。 デフォルトで反復可能でないJavaScriptタイプは、反復可能プロトコルを使用して反復できます。

次の例では、複数の顧客オブジェクトを配列として格納する CustomerList という名前のクラスを定義しています。 各顧客オブジェクトには、firstNameプロパティとlastNameプロパティがあります。

このクラスを反復可能にするには、クラスが* [Symbol.iterator]()関数を実装する必要があります。 この関数は、反復子オブジェクトを返します。 イテレータオブジェクトには、オブジェクト *\ {value: 'customer'、done:true/false} を返す関数 next があります。

<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には、途中で停止し、停止したところから続行できるジェネレーターと呼ばれる機能が導入されています。

ジェネレーターは、関数名の前にアスタリスク*文字を付け、1つ以上の yield ステートメントを含みます。 yield キーワードはイテレーターオブジェクトを返します。

構文

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

この例では、3つのyieldステートメントでジェネレーター関数 getMarks を定義しています。 通常の関数とは異なり、* generator関数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