ES6 - Iteratore

Introduzione a Iterator

Iterator è un oggetto che ci permette di accedere a una raccolta di oggetti uno alla volta.

I seguenti tipi incorporati sono iterabili per impostazione predefinita:

  • String
  • Array
  • Map
  • Set

Viene considerato un oggetto iterable, se l'oggetto implementa una funzione la cui chiave è [Symbol.iterator]e restituisce un iteratore. Un ciclo for ... of può essere utilizzato per iterare una raccolta.

Esempio

L'esempio seguente dichiara una matrice, contrassegna e scorre attraverso di essa utilizzando un file for..of ciclo continuo.

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

L'output del codice sopra sarà come indicato di seguito:

10
20
30

Esempio

L'esempio seguente dichiara un array, contrassegna e recupera un oggetto iteratore. Il[Symbol.iterator]()può essere utilizzato per recuperare un oggetto iteratore. Il metodo next () dell'iteratore restituisce un oggetto con'value' e 'done'proprietà . "done" è booleano e restituisce true dopo aver letto tutti gli elementi nella raccolta.

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

L'output del codice sopra sarà come mostrato di seguito -

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

Iterabile personalizzato

Alcuni tipi in JavaScript sono iterabili (ad es. Array, Map ecc.) Mentre altri non lo sono (ad es. Class). I tipi JavaScript che non sono iterabili per impostazione predefinita possono essere iterati utilizzando il protocollo iterabile.

L'esempio seguente definisce una classe denominata CustomerListche memorizza più oggetti cliente come un array. Ogni oggetto cliente ha proprietà firstName e lastName.

Per rendere iterabile questa classe, la classe deve implementare [Symbol.iterator]()funzione. Questa funzione restituisce un oggetto iteratore. L'oggetto iteratore ha una funzionenext che restituisce un oggetto {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>

L'output del codice precedente sarà il seguente:

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

Generatore

Prima di ES6, le funzioni in JavaScript seguivano un modello run-to-complete. ES6 introduce funzioni note come Generatore che possono interrompersi a metà e poi continuare da dove si erano fermate.

Un generatore antepone al nome della funzione un carattere asterisco * e ne contiene uno o più yielddichiarazioni. Ilyield la parola chiave restituisce un oggetto iteratore.

Sintassi

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

Esempio

L'esempio definisce una funzione del generatore getMarkscon tre dichiarazioni di rendimento. A differenza delle normali funzioni, ilgenerator function getMarks(), quando invocato, non esegue la funzione ma restituisce un oggetto iteratore che aiuta a eseguire il codice all'interno della funzione generatore.

Alla prima chiamata a markIter.next()le operazioni all'inizio verrebbero eseguite e l'istruzione yield interrompe l'esecuzione del generatore. Successive chiamate almarkIter.next() riprenderà la funzione generatore fino al successivo yield espressione.

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

L'output del codice sopra sarà come indicato di seguito -

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}

Esempio

L'esempio seguente crea una sequenza infinita di numeri pari

* evenNumberGenerator funzione del generatore.

Possiamo scorrere tutti i numeri pari utilizzando next() o utilizzando for of loop come mostrato di seguito

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

L'output del codice precedente sarà il seguente:

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