解释
让一个对象成为可迭代对象意味着该对象具有名为 Symbol.iterator
的方法。当调用此方法时,它应返回一个名为iterator的接口。
这个迭代器必须具有一个next
方法,该方法返回下一个结果。这个结果应该是一个带有value
属性的对象,该属性提供下一个值,并且应该有一个done
属性,当没有更多结果时应该是true
,否则为false
。
实现
我还将为名为Matrix
的类实现一个迭代器,其中所有元素的范围将从0
到width * height - 1
。我将为此迭代器创建一个不同的类,名为MatrixIterator
。
class Matrix {
constructor(width, height) {
this.width = width;
this.height = height;
this.content = [];
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
this.content[y * width + x] = y * width + x;
}
}
}
get(x, y) {
return this.content[y * this.width + x];
}
[Symbol.iterator]() {
return new MatrixIterator(this);
}
}
class MatrixIterator {
constructor(matrix) {
this.x = 0;
this.y = 0;
this.matrix = matrix;
}
next() {
if (this.y == this.matrix.height) return {done: true};
let value = {
x: this.x,
y: this.y,
value: this.matrix.get(this.x, this.y)
};
this.x++;
if (this.x == this.matrix.width) {
this.x = 0;
this.y++;
}
return {value, done: false};
}
}
注意,
Matrix
通过定义
Symbol.iterator
符号实现了
iterator 协议。在这个方法内部,创建了一个
MatrixIterator
实例,该实例将
this
,即
Matrix
实例作为参数,并且在
MatrixIterator
内部定义了
next
方法。我特别喜欢使用这种方式来实现迭代器,因为它清晰地展示了迭代器和
Symbol.iterator
的实现方式。
另外,也可以不直接定义
Symbol.iterator
,而是向
prototype[Symbol.iterator]
添加一个函数,如下所示:
Matrix.prototype[Symbol.iterator] = function() {
return new MatrixIterator(this);
};
使用示例
let matrix = new Matrix(3, 2);
for (let e of matrix) {
console.log(e);
}
v8.1.1
版本的 Node 中运行良好。 - Shaheen Ghiassy