Iterator() Konstruktor

Baseline 2025
Newly available

Since March 2025, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

Der Iterator()-Konstruktor ist vorgesehen, um als Superklasse anderer Klassen verwendet zu werden, die Iteratoren erstellen. Wenn er eigenständig konstruiert wird, wirft er einen Fehler.

Syntax

js
new Iterator()

Hinweis:>Iterator() kann nur mit new konstruiert werden. Ein Versuch, ihn ohne new aufzurufen, wirft einen TypeError. Darüber hinaus kann Iterator() selbst nicht tatsächlich konstruiert werden — er wird normalerweise implizit durch Aufrufe von super() im Konstruktor einer Unterklasse erstellt.

Parameter

Keine.

Rückgabewert

Ein neues Iterator-Objekt.

Ausnahmen

TypeError

Wenn new.target die Iterator-Funktion selbst ist, d.h. wenn der Iterator-Konstruktor selbst konstruiert wird.

Beschreibung

Iterator stellt eine abstrakte Klasse dar — eine Klasse, die allgemeine Werkzeuge für ihre Unterklassen bereitstellt, selbst jedoch nicht instanziiert werden soll. Sie ist die Superklasse aller anderen Iterator-Klassen und wird genutzt, um Unterklassen zu erstellen, die spezifische Iterationsalgorithmen implementieren — nämlich, alle Unterklassen von Iterator müssen eine next()-Methode implementieren, wie es durch das Iterator-Protokoll verlangt wird. Da Iterator die next()-Methode tatsächlich nicht bereitstellt, macht es keinen Sinn, einen Iterator direkt zu konstruieren.

Sie können auch Iterator.from() verwenden, um eine Iterator-Instanz aus einem vorhandenen Iterable- oder Iterator-Objekt zu erstellen.

Beispiele

Subclassing von Iterator

Das folgende Beispiel definiert eine benutzerdefinierte Datenstruktur, Range, die Iteration ermöglicht. Um ein Objekt iterierbar zu machen, können wir eine [Symbol.iterator]()-Methode in Form einer Generatorfunktion bereitstellen:

js
class Range {
  #start;
  #end;
  #step;

  constructor(start, end, step = 1) {
    this.#start = start;
    this.#end = end;
    this.#step = step;
  }

  *[Symbol.iterator]() {
    for (let value = this.#start; value <= this.#end; value += this.#step) {
      yield value;
    }
  }
}

const range = new Range(1, 5);
for (const num of range) {
  console.log(num);
}

Dies funktioniert, ist aber nicht so elegant wie die Arbeitsweise der eingebauten Iteratoren. Es gibt zwei Probleme:

  • Der zurückgegebene Iterator erbt von Generator, was bedeutet, dass Änderungen an Generator.prototype den zurückgegebenen Iterator betreffen, was ein Leck der Abstraktion darstellt.
  • Der zurückgegebene Iterator erbt nicht von einem benutzerdefinierten Prototyp, was es schwieriger macht, wenn wir beabsichtigen, zusätzliche Methoden zum Iterator hinzuzufügen.

Wir können die Implementierung eingebauter Iteratoren, wie z.B. Karten-Iteratoren, nachahmen, indem wir Iterator erweitern. Dies ermöglicht es uns, zusätzliche Eigenschaften wie [Symbol.toStringTag] zu definieren, während die Iterator-Hilfsmethoden auf dem zurückgegebenen Iterator verfügbar sind.

js
class Range {
  #start;
  #end;
  #step;

  constructor(start, end, step = 1) {
    this.#start = start;
    this.#end = end;
    this.#step = step;
  }

  static #RangeIterator = class extends Iterator {
    #cur;
    #s;
    #e;
    constructor(range) {
      super();
      this.#cur = range.#start;
      this.#s = range.#step;
      this.#e = range.#end;
    }
    static {
      Object.defineProperty(this.prototype, Symbol.toStringTag, {
        value: "Range Iterator",
        configurable: true,
        enumerable: false,
        writable: false,
      });

      // Avoid #RangeIterator from being accessible outside
      delete this.prototype.constructor;
    }
    next() {
      if (this.#cur > this.#e) {
        return { value: undefined, done: true };
      }
      const res = { value: this.#cur, done: false };
      this.#cur += this.#s;
      return res;
    }
  };

  [Symbol.iterator]() {
    return new Range.#RangeIterator(this);
  }
}

const range = new Range(1, 5);
for (const num of range) {
  console.log(num);
}

Das Subclassing-Muster ist nützlich, wenn Sie viele benutzerdefinierte Iteratoren erstellen möchten. Wenn Sie ein vorhandenes Iterable- oder Iterator-Objekt haben, das nicht von Iterator erbt, und Sie nur die Iterator-Hilfsmethoden darauf aufrufen möchten, können Sie Iterator.from() verwenden, um eine einmalige Iterator-Instanz zu erstellen.

Spezifikationen

Specification
Iterator Helpers
# sec-iterator-constructor

Browser-Kompatibilität

Siehe auch