Diese Übersetzung ist unvollständig. Bitte helfen Sie, diesen Artikel aus dem Englischen zu übersetzen.

Das Iterieren über eine Liste bzw. das Verarbeiten jedes Elements einer Liste ist eine häufige Operation, für die es in JavaScript mehrere Möglichkeiten gibt. Zum Beispiel einfache for-Schleifen oder Array Operationen, wie map() und filter().
Iteratoren und Generatoren bringen das Konzept des Itererierens über eine Liste in den Kern der Sprache und bieten im Speziellen die Möglichkeit das Verhalten von for...of-Schleifen anzupassen.

For details, see also:

Iteratoren

Ein Objekt ist ein Iterator, wenn es einen einzelnen Eintrag aus einer Sammlung abrufen kann, während es sich die aktuelle Position in dieser Abfolge merkt. In JavaScript ist ein Iterator ein Objekt, das eine  next()-Methode zur Verfügung stellt, welche den nächsten Eintrag in der Sequenz zurückgibt.
Diese Methode gibt ein Objekt mit zwei Eigenschaften zurück: done und value.

Ein Iterator gilt als abgeschlossen bzw. beendet, wenn die next()-Methode ein Objekt mit der Eigenschaft done mit dem Wert true zurückgibt.

Einmal erstellt, kann ein Iterator-Objekt explizit verwendet werden, indem wiederholt next() aufgerufen wird, um nacheinander auf Schlüssel-Wert-Paare vom Objekt zuzugreifen:

const makeIterator = (someArray) => {
  let nextIndex = 0;
  return {
    next: () => {
      if (nextIndex < someArray.length) {
        return {
          value: someArray[nextIndex++],
          done: false
        };
      }
      return {
        done: true
      };
    }
  };
}

const sampleList = document.getElementById('sample-list')
const iterator = makeIterator(['foo', 'bar']);
let result = iterator.next();
while (!result.done) {
  sampleList.innerHTML += '<li>Next: ' + result.value + '</li>';
  result = iterator.next();
}
<p>Eine Liste, die mit den Werten aus dem Iterator erweitert wird:</p>
<ul id="sample-list"></ul>

Generators

While custom iterators are a useful tool, their creation requires careful programming due to the need to explicitly maintain their internal state. Generators provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function which can maintain its own state.

A GeneratorFunction is a special type of function that works as a factory for iterators. When it is executed it returns a new Generator object. A function becomes a GeneratorFunction if it uses the function* syntax.

function* idMaker() {
  var index = 0;
  while(true)
    yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// ...

Iterables

An object is iterable if it defines its iteration behavior, such as what values are looped over in a for...of construct. Some built-in types, such as Array or Map, have a default iteration behavior, while other types (such as Object) do not.

In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a Symbol.iterator key. This function should return a new iterator for each call, however, this is not a requirement.

User-defined iterables

We can make our own iterables like this:

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};

for (let value of myIterable) { 
    console.log(value); 
}
// 1
// 2
// 3

or

[...myIterable]; // [1, 2, 3]

Built-in iterables

String, Array, TypedArray, Map and Set are all built-in iterables, because their prototype objects all have a Symbol.iterator method.

Syntaxes expecting iterables

Some statements and expressions are expecting iterables, for example the for-of loops, spread syntax, yield*, and destructuring assignment.

for (let value of ['a', 'b', 'c']) {
    console.log(value);
}
// "a"
// "b"
// "c"

[...'abc']; // ["a", "b", "c"]

function* gen() {
  yield* ['a', 'b', 'c'];
}

gen().next(); // { value: "a", done: false }

[a, b, c] = new Set(['a', 'b', 'c']);
a; // "a"

Advanced generators

Generators compute their yielded values on demand, which allows them to efficiently represent sequences that are expensive to compute, or even infinite sequences as demonstrated above.

The next() method also accepts a value which can be used to modify the internal state of the generator. A value passed to next() will be treated as the result of the last yield expression that paused the generator.

Here is the fibonacci generator using next(x) to restart the sequence:

function* fibonacci() {
  var fn1 = 0;
  var fn2 = 1;
  while (true) {  
    var current = fn1;
    fn1 = fn2;
    fn2 = current + fn1;
    var reset = yield current;
    if (reset) {
        fn1 = 0;
        fn2 = 1;
    }
  }
}

var sequence = fibonacci();
console.log(sequence.next().value);     // 0
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 2
console.log(sequence.next().value);     // 3
console.log(sequence.next().value);     // 5
console.log(sequence.next().value);     // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 2

You can force a generator to throw an exception by calling its throw() method and passing the exception value it should throw. This exception will be thrown from the current suspended context of the generator, as if the yield that is currently suspended were instead a throw value statement.

If the exception is not caught from within the generator, it will propagate up through the call to throw(), and subsequent calls to next() will result in the done property being true.

Generators have a return(value) method that returns the given value and finishes the generator itself.

Schlagwörter des Dokuments und Mitwirkende

Mitwirkende an dieser Seite: timvancleef, Nadt, roNn23, schlagi123, fscholz, janchristoph, eminor
Zuletzt aktualisiert von: timvancleef,