在 JavaScript
中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。 更具体地说,迭代器是通过使用 next()
方法实现 Iterator protocol
的任何一个对象,该方法返回具有两个属性的对象: value
,这是序列中的 next 值;和 done
,如果已经迭代到序列中的最后一个值,则它为 true
。如果 value
和 done
一起存在,则它是迭代器的返回值。
一旦创建,迭代器对象可以通过重复调用 next()
显式地迭代。 迭代一个迭代器被称为消耗了这个迭代器,因为它通常只能执行一次。 在产生终止值之后,对next()
的额外调用应该继续返回 {done:true}
。
Javascript
中最常见的迭代器是 Array
迭代器,它只是按顺序返回关联数组中的每个值。 虽然很容易想象所有迭代器都可以表示为数组,但事实并非如此。 数组必须完整分配,但迭代器仅在必要时使用,因此可以表示无限大小的序列,例如0和无穷大之间的整数范围。
在项目中实际使用的简单的迭代器可能如下示例:
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: 'Frank' },
{ complete: true, value: 'Jack' },
{ complete: false },
{ complete: true, value: 'James' },
]);
for (let item of myList) {
console.log(item); // 将确切数据传递给上面的特别列表构造器
}
for (let item of myList.values()) {
console.log(item); // 'Frank', 'Jack', 'James'
}
在这个例子中,我们使用data
对象的本身数组的迭代器来使我们的SpecialList
可迭代,返回data
数组的确切值。同时,我们还定义了一个values
方法,它本身就是一个迭代器,在数组上使用Array.prototype.filter()
和 Array.prototype.map()
。最后,我们返回结果的Symbol.iterator
,只允许对序列中的非空对象进行迭代,并仅返回每个对象的 value
。