JavaScript 迭代器是什么,以及在哪里可以使用它们?

JavaScript 迭代器是在 ES6 中引入的,它们用于循环遍历一系列的值,通常是某种集合。根据定义,迭代器必须实现一个 next() 函数,该函数返回一个形如 { value, done } 的对象,其中 value 是迭代序列中的下一个值,done 是一个布尔值,用于确定序列是否已经被消耗完。

一个在实际项目中有实际用途的非常简单的迭代器可以如下所示:

class LinkedList {
  constructor(data) {
    this.data = data;
  }

  firstItem() {
    return this.data.find(i => i.head);
  }

  findById(id) {
    return this.data.find(i => i.id === id);
  }

  [Symbol.iterator]() {
    let item = { next: this.firstItem().id };
    return {
      next: () => {
        item = this.findById(item.next);
        if (item) {
          return { value: item.value, done: false };
        }
        return { value: undefined, done: true };
      },
    };
  }
}

const myList = new LinkedList([
  { id: 'a10', value: 'First', next: 'a13', head: true },
  { id: 'a11', value: 'Last', next: null, head: false },
  { id: 'a12', value: 'Third', next: 'a11', head: false },
  { id: 'a13', value: 'Second', next: 'a12', head: false },
]);

for (let item of myList) {
  console.log(item); // 'First', 'Second', 'Third', 'Last'
}

在上面的示例中,我们实现了一个 LinkedList 数据结构,它在内部使用一个 data 数组。其中的每个项都有一个 value 和一些特定于实现的属性,用于确定它在序列中的位置。从该类构造的对象默认情况下不可迭代。为了定义一个迭代器,我们使用 Symbol.iterator 并设置它,使得返回的序列基于类的内部实现按顺序排列,而返回的项仅返回它们的 value

相关的是,迭代器只是函数,意味着它们可以像其他函数一样被调用(例如将迭代委托给现有的迭代器),同时不受Symbol.iterator名称的限制。这使我们能够为同一个对象定义多个迭代器。下面是一个示例,展示了这些概念的运用:

class SpecialList {
  constructor(data) {
    this.data = data;
  }

  [Symbol.iterator]() {
    return this.data[Symbol.iterator]();
  }

  values() {
    return this.data
      .filter(i => i.complete)
      .map(i => i.value)
      [Symbol.iterator]();
  }
}

const myList = new SpecialList([
  { complete: true, value: 'Lorem ipsum' },
  { complete: true, value: 'dolor sit amet' },
  { complete: false },
  { complete: true, value: 'adipiscing elit' },
]);

for (let item of myList) {
  console.log(item); // 与上面传递给SpecialList构造函数的确切数据相同
}

for (let item of myList.values()) {
  console.log(item); // 'Lorem ipsum', 'dolor sit amet', 'adipiscing elit'
}

在这个示例中,我们使用data对象的原生数组迭代器使我们的SpecialList可迭代,返回data数组的确切值。同时,我们还定义了一个values方法,它本身就是一个迭代器,使用Array.prototype.filter()Array.prototype.map()data数组上进行操作。最后,我们返回结果的Symbol.iterator,只允许在序列中迭代非空对象,并且只返回每个对象的value