说明
制作一个对象可迭代意味着这个对象有一个以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方法。我特别喜欢这种实现迭代器的方式,因为它清楚地显示了 iterator 和 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);
}