Iterator() コンストラクター

Limited availability

This feature is not Baseline because it does not work in some of the most widely-used browsers.

Iterator() コンストラクターは、イテレーターを作成する他のクラスのスーパークラスとして意図通りに使用されることを目的としています。これ自体で構築された場合、エラーが発生します。

構文

js
new Iterator()

メモ: Iterator()new でしか作成できません。 new を使用せずに名付けると TypeError が発生します。さらに、 Iterator() は実際にはそれ自体で作成することはできません。通常は、サブクラスのコンストラクター内で super() を呼び出すことで暗黙的に作成されます。

引数

なし。

返値

新しい Iterator オブジェクトです。

例外

TypeError

new.targetIterator 関数事態に呼び出された場合、つまり、 Iterator コンストラクターそれ自身が構築された場合。

解説

Iterator は抽象クラスを表します。抽象クラスとは、サブクラスに対して指定された共通のユーティリティを提供するクラスですが、それ自体がインスタンス化されることを意図していません。これは、他にもイテレータークラスのスーパークラスであり、特定の反復処理アルゴリズムを実装するサブクラスを作成するために使用されます。つまり、 Iterator のすべてのサブクラスは、イテレータープロトコルで要求されるように、 next() メソッドを実装する必要があります。 Iterator は実際には next() メソッドを提供していないため、 Iterator を直接構築することは意味がありません。

また、 Iterator.from() を使用して、既存の反復可能オブジェクトまたはイテレーターオブジェクトから Iterator のインスタンスを作成することもできます。

Iterator のサブクラス化

次の例では、反復処理が可能なカスタムデータ構造である Range を定義しています。オブジェクトを反復処理可能にするには、ジェネレーター関数という形で [Symbol.iterator]() メソッドを提供します。

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);
}

これはうまく動作しますが、組み込みのイテレーターの作業方法ほど優れてはいません。 2 つの問題があります。

  • 返されたイテレーターは Generator を継承しており、これは Generator.prototype への変更が返されたイテレーターに影響することを意味しており、抽象化の漏れです。
  • 返されたイテレーターはカスタムプロトタイプを継承しないため、イテレーターに追加のメソッドを意図通りに追加するのが難しくなります。

Iterator をサブクラス化することで、組み込みのイテレーター(例えば、マップのイテレーター)の実装を模倣することができます。これにより、 [Symbol.toStringTag] などの追加のプロパティを定義することができ、返値のイテレーターにおいてイテレーターのヘルパーメソッドを利用できるようになります。

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);
}

サブクラス化パターンは、多数の独自のイテレーターを作成したい場合に便利です。 Iterator を継承していない反復可能オブジェクトやイテレーターオブジェクトがあり、そのオブジェクトにイテレーターのヘルパーメソッドを呼び出したいだけの場合、 Iterator.from() を使用して、一時的に Iterator インスタンスを作成することができます。

仕様書

Specification
Iterator Helpers
# sec-iterator-constructor

ブラウザーの互換性

BCD tables only load in the browser

関連情報