From 4b1a9203c547c019fc5398082ae19a3f3d4c3efe Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:15 -0500 Subject: initial commit --- .../reference/iteration_protocols/index.html | 349 +++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 files/de/web/javascript/reference/iteration_protocols/index.html (limited to 'files/de/web/javascript/reference/iteration_protocols/index.html') diff --git a/files/de/web/javascript/reference/iteration_protocols/index.html b/files/de/web/javascript/reference/iteration_protocols/index.html new file mode 100644 index 0000000000..f1ecbe29a1 --- /dev/null +++ b/files/de/web/javascript/reference/iteration_protocols/index.html @@ -0,0 +1,349 @@ +--- +title: Iterations Protokolle +slug: Web/JavaScript/Reference/Iteration_protocols +tags: + - ECMAScript 2015 + - Intermediate + - Iterable + - Iterator + - JavaScript +translation_of: Web/JavaScript/Reference/Iteration_protocols +--- +
{{jsSidebar("More")}}
+ +

Einige Änderungen in ECMAScript 2015 sind keine neuen Objekte oder Syntax, sondern Protokolle. Diese Protokolle können von jedem Objekt implementiert werden, wenn einige Konventionen eingehalten werden.

+ +

Es gibt zwei Protokolle: Das Iterierbare (iterable) Protokoll und das Iterator Protokoll

+ +

Das Iterierbare (iterable) Protokoll

+ +

Das Iterierbare (iterable) Protokoll erlaubt es bei JavaScript-Objekten das Iterierverhalten zu definieren oder anzupassen, wie z. B. wie Werte in einem {{jsxref("Statements/for...of", "for..of")}} Konstrukt durchlaufen werden. Einige Standardtypen sind von sich aus schon Iterierbar mit einem Standarditerationsverhalten, so wie {{jsxref("Array")}} oder {{jsxref("Map")}}, wohingegen andere Typen (so wie {{jsxref("Object")}}) nicht Iterierbar sind.

+ +

Um Iterierbar zu sein, muss ein Objekt die @@iterator Methode implementieren, was bedeutet, dass das Objekte (oder ein Objekt weiter oben in der Prototypenkette) eine Eigenschaft mit dem @@iterator Schlüssel haben muss, welcher über die Konstante {{jsxref("Symbol.iterator")}} erreichbar ist:

+ + + + + + + + + + + + + + +
EigenschaftWert
[Symbol.iterator]Eine Funktion ohne Parameter, welche ein Objekt zurückgibt, welches dem Iterator Protokoll entspricht.
+ +

Immer wenn ein Objekt iteriert werden soll (z. B. am Anfang einer for..of Schleife), wird die @@iterator Methode mit keinem Argument aufgerufen und der zurückgegebene Iterator wird benutzt, um die zu iterierenden Werte zu bekommen.

+ +

Das Iterator Protokoll

+ +

Das Iterator Protokoll definiert einen Standardweg, um eine Sequenz von Werte (endlich oder unendlich lang) zu produzieren.

+ +

Ein Objekt ist ein Iterator, wenn es die Methode next() mit folgender Semantik implementiert:

+ + + + + + + + + + + + +
EigenschaftWert
next +

Eine Funktion ohne Parameter, welche ein Objekt mit zwei Eigenschaften zurückgibt:

+ +
    +
  • done (boolean) + +
      +
    • Hat den Wert true, wenn der Iterator das Ende der Iterierten Sequenz erreicht hat. In diesem Fall ist value ein optional spezifizierter Rückgabewert des Iterators. Der Rückgabewert ist hier näher erklärt.
    • +
    • Hat den Wert false, wenn der Iterator weitere Werte aus der Sequenz produzieren kann. Äquivalent ist, wenn die done Eigenschaft nicht definiert wird.
    • +
    +
  • +
  • value - ein JavaScript Wert, der vom Iterator zurückgegeben wird. Kann weggelassen werden, wenn done den Wert true hat.
  • +
+ +

Die next Methode gibt immer ein Objekt mit den Eigenschaften done und value zurück. Wird kein Objekt zurückgegeben (wie z. B. false oder undefined), wird ein {{jsxref("TypeError")}} ("iterator.next() returned a non-object value") erzeugt.

+
+ +

Einige Iteratoren sind wiederum iterierbar:

+ +
var someArray = [1, 5, 7];
+var someArrayEntries = someArray.entries();
+
+someArrayEntries.toString();           // "[object Array Iterator]"
+someArrayEntries === someArrayEntries[Symbol.iterator]();    // true
+
+ +

Beispiele für den Einsatz de Iterations Protokolle

+ +

Ein {{jsxref("String")}} ist ein Beispiel für ein standard iterierbares Objekt:

+ +
var someString = 'hi';
+typeof someString[Symbol.iterator];          // "function"
+
+ +

Der Standard Iteratior von Strings gibt die Codepoints einen nach dem anderen zurück:

+ +
var iterator = someString[Symbol.iterator]();
+iterator + '';                               // "[object String Iterator]"
+
+iterator.next();                             // { value: "h", done: false }
+iterator.next();                             // { value: "i", done: false }
+iterator.next();                             // { value: undefined, done: true }
+ +

Einige Standardkonstrukte, wie z. B. die Spread Syntax, benutzen unter der Decke das selbe Iterierbare Protokoll

+ +
[...someString]                              // ["h", "i"]
+ +

Man kann das Iterierverhalben neu definieren indem eine eigene @@iterator Eigenschaft definiert wird:

+ +
var someString = new String('hi');           // need to construct a String object explicitly to avoid auto-boxing
+
+someString[Symbol.iterator] = function() {
+  return { // this is the iterator object, returning a single element, the string "bye"
+    next: function() {
+      if (this._first) {
+        this._first = false;
+        return { value: 'bye', done: false };
+      } else {
+        return { done: true };
+      }
+    },
+    _first: true
+  };
+};
+
+ +

Zu bemerken ist, dass die Neudefinition von @@iterator hat Effekte auf Standardkonstrukte, die das Iterierbare Protokoll benutzen;

+ +
[...someString];                             // ["bye"]
+someString + '';                             // "hi"
+
+ +

Iterierbare Beispiele

+ +

Standard iterierbare Objekte

+ +

{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} und {{jsxref("Set")}} sind im Standard iterierbar, weil jeder Prototyp der Objekte eine @@iterator Methode definiert.

+ +

Benutzerdefiniertes Iterierbares Objekt

+ +

Man kann eigene Iterierbare Objekte wie folgt erstellen:

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

Standard APIs akzeptieren Iterierbare Objekte

+ +

Es gibt viele APIs, die iterierbare Objekte akzeptieren, zum Beispiel: {{jsxref("Map", "Map([iterable])")}}, {{jsxref("WeakMap", "WeakMap([iterable])")}}, {{jsxref("Set", "Set([iterable])")}} and {{jsxref("WeakSet", "WeakSet([iterable])")}}:

+ +
var myObj = {};
+new Map([[1, 'a'], [2, 'b'], [3, 'c']]).get(2);               // "b"
+new WeakMap([[{}, 'a'], [myObj, 'b'], [{}, 'c']]).get(myObj); // "b"
+new Set([1, 2, 3]).has(3);                               // true
+new Set('123').has('2');                                 // true
+new WeakSet(function* () {
+    yield {};
+    yield myObj;
+    yield {};
+}()).has(myObj);                                         // true
+
+ +

Zudem sollten {{jsxref("Promise.all", "Promise.all(iterable)")}}, {{jsxref("Promise.race", "Promise.race(iterable)")}}, and {{jsxref("Array.from", "Array.from()")}} angeschaut werden.

+ +

Syntaxen die iterierbare Objekte erwarten

+ +

Einige Statements und Ausdrücke erwarten iterierbare Objekt, zum Beispiel die for-of Schleife, Spread Syntax, yield* und destrukturierende Zuweisungen:

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

Nicht richtig definierte iterierbare Objekte

+ +

Wenn eine iterierbare @@iterator Methode keinen Iterator Objekt zurück gibt, ist es nicht richtig definiert. Wenn es so benutzt wird, führt das zu Laufzeitfehlern oder unerwartetem Verhalten:

+ +
var nonWellFormedIterable = {}
+nonWellFormedIterable[Symbol.iterator] = () => 1
+[...nonWellFormedIterable] // TypeError: [] is not a function
+
+ +

Iterator Beispiele

+ +

Einfacher Iterator

+ +
function makeIterator(array) {
+    var nextIndex = 0;
+
+    return {
+       next: function() {
+           return nextIndex < array.length ?
+               {value: array[nextIndex++], done: false} :
+               {done: true};
+       }
+    };
+}
+
+var it = makeIterator(['yo', 'ya']);
+
+console.log(it.next().value); // 'yo'
+console.log(it.next().value); // 'ya'
+console.log(it.next().done);  // true
+
+ +

Unendlicher Iterator

+ +
function idMaker() {
+    var index = 0;
+
+    return {
+       next: function(){
+           return {value: index++, done: false};
+       }
+    };
+}
+
+var it = idMaker();
+
+console.log(it.next().value); // '0'
+console.log(it.next().value); // '1'
+console.log(it.next().value); // '2'
+// ...
+
+ +

Mit einem Generator

+ +
function* makeSimpleGenerator(array) {
+    var nextIndex = 0;
+
+    while (nextIndex < array.length) {
+        yield array[nextIndex++];
+    }
+}
+
+var gen = makeSimpleGenerator(['yo', 'ya']);
+
+console.log(gen.next().value); // 'yo'
+console.log(gen.next().value); // 'ya'
+console.log(gen.next().done);  // true
+
+
+
+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'
+// ...
+
+ +

Mit ES2015 Klassen (class)

+ +
class SimpleClass {
+  constructor(data) {
+    this.index = 0;
+    this.data = data;
+  }
+
+  [Symbol.iterator]() {
+    return {
+      next: () => {
+        if (this.index < this.data.length) {
+          return {value: this.data[this.index++], done: false};
+        } else {
+          this.index = 0; //If we would like to iterate over this again without forcing manual update of the index
+          return {done: true};
+        }
+      }
+    }
+  };
+}
+
+const simple = new SimpleClass([1,2,3,4,5]);
+
+for (const val of simple) {
+  console.log(val);  //'0' '1' '2' '3' '4' '5'
+}
+
+ +

Ist ein Generator Objekt ein Iterator oder ein iterierbares Objekt?

+ +

Ein Generatorobjekt ist beides, Iterator und Iterierbar:

+ +
var aGeneratorObject = function* () {
+    yield 1;
+    yield 2;
+    yield 3;
+}();
+typeof aGeneratorObject.next;
+// "function", because it has a next method, so it's an iterator
+typeof aGeneratorObject[Symbol.iterator];
+// "function", because it has an @@iterator method, so it's an iterable
+aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
+// true, because its @@iterator method returns itself (an iterator), so it's an well-formed iterable
+[...aGeneratorObject];
+// [1, 2, 3]
+
+ +

Spezifikationen

+ + + + + + + + + + + + + + + + + + + +
SpezifikationStatusKommentar
{{SpecName('ES2015', '#sec-iteration', 'Iteration')}}{{Spec2('ES2015')}}Initiale Definition.
{{SpecName('ESDraft', '#sec-iteration', 'Iteration')}}{{Spec2('ESDraft')}}
+ +

Siehe auch

+ + -- cgit v1.2.3-54-g00ecf