Iterator() 构造函数

实验性: 这是一项实验性技术
在将其用于生产之前,请仔细检查浏览器兼容性表格

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。使一个对象可迭代最简单的方法是提供一个生成器函数的形式的 [@@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);
}

上面的代码是可行的,但它不如内置的迭代器。有两个问题:

  • 返回的迭代器继承自 Generator,这意味着对 Generator.prototype 的修改将会影响返回的迭代器,这是一种抽象泄漏。
  • 返回的迭代器没有继承自自定义原型,这使得为迭代器添加额外的方法变得更加困难。

我们可以通过继承 Iterator 来模仿内置迭代器,例如 map 迭代器的实现。这使得我们可以定义额外的属性,例如 @@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,
      });

      // 避免 #RangeIterator 被外部访问
      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

参见