如何使用 ES6 class 制作迭代器
How to make an iterator out of an ES6 class
我如何以与 JS1.7 SomeClass.prototype.__iterator__ = function() {...}
语法相同的方式从 ES6 class 中创建迭代器?
[编辑16:00]
以下作品:
class SomeClass {
constructor() {
}
*[Symbol.iterator]() {
yield '1';
yield '2';
}
//*generator() {
//}
}
an_instance = new SomeClass();
for (let v of an_instance) {
console.log(v);
}
WebStorm 直接在星号之后用 'function name expected' 警告标记 *[Symbol.iterator]()
,但除此之外,它可以通过 Traceur 正常编译和运行。 (注意 WebStorm 不会为 *generator()
生成任何错误。)
您需要为 SomeClass
指定 Symbol.iterator
属性,为 class 实例指定 returns iterator。迭代器必须有 next()
方法, 反过来 returns 对象有 done
和 value
字段。简化示例:
function SomeClass() {
this._data = [1,2,3,4];
}
SomeClass.prototype[Symbol.iterator] = function() {
var index = 0;
var data = this._data;
return {
next: function() {
return { value: data[++index], done: !(index in data) }
}
};
};
或者使用 ES6 classes 和箭头函数:
class SomeClass {
constructor() {
this._data = [1,2,3,4];
}
[Symbol.iterator]() {
var index = -1;
var data = this._data;
return {
next: () => ({ value: data[++index], done: !(index in data) })
};
};
}
和用法:
var obj = new SomeClass();
for (var i of obj) { console.log(i) }
在你更新的问题中,你通过生成器函数实现了class迭代器。你可以这样做,但你必须明白迭代器不能是生成器。实际上 es6 中的迭代器是任何具有特定 next()
method
的对象
定义合适的迭代器方法。例如:
class C {
constructor() { this.a = [] }
add(x) { this.a.push(x) }
[Symbol.iterator]() { return this.a.values() }
}
编辑:示例使用:
let c = new C
c.add(1); c.add(2)
for (let i of c) console.log(i)
这是一个在 ES6
中迭代二维矩阵自定义 class 的示例
class Matrix {
constructor() {
this.matrix = [[1, 2, 9],
[5, 3, 8],
[4, 6, 7]];
}
*[Symbol.iterator]() {
for (let row of this.matrix) {
for (let cell of row) {
yield cell;
}
}
}
}
这种 class 的用法是
let matrix = new Matrix();
for (let cell of matrix) {
console.log(cell)
}
哪个会输出
1
2
9
5
3
8
4
6
7
实施迭代器协议和可迭代协议技术的示例class:
class MyCollection {
constructor(elements) {
if (!Array.isArray(elements))
throw new Error('Parameter to constructor must be array');
this.elements = elements;
}
// Implement "iterator protocol"
*iterator() {
for (let key in this.elements) {
var value = this.elements[key];
yield value;
}
}
// Implement "iterable protocol"
[Symbol.iterator]() {
return this.iterator();
}
}
使用任一技术访问元素:
var myCollection = new MyCollection(['foo', 'bar', 'bah', 'bat']);
// Access elements of the collection using iterable
for (let element of myCollection)
console.log('element via "iterable": ' + element);
// Access elements of the collection using iterator
var iterator = myCollection.iterator();
while (element = iterator.next().value)
console.log('element via "iterator": ' + element);
存储在子对象中的 ES6 迭代器示例 class:
class Iterator {
data;
constructor(data = {}) {
this.data = JSON.parse(JSON.stringify(data));
}
add(key, value) { this.data[key] = value; }
get(key) { return this.data[key]; }
[Symbol.iterator]() {
const keys = Object.keys(this.data).filter(key =>
this.data.hasOwnProperty(key));
const values = keys.map(key => this.data[key]).values();
return values;
}
}
说明
使一个对象可迭代意味着这个对象有一个以Symbol.iterator
命名的方法。调用此方法时,它应该 return 一个名为 iterator.
的接口
这个迭代器必须有一个方法next
,return是下一个结果。这个结果应该是一个对象,带有提供下一个值的 value
属性 和 done
属性,当没有更多时应该是 true
结果和 false
否则。
实施
我还将为一个名为 Matrix
的 class 实现一个迭代器,其中所有元素的范围从 0
到 width * height - 1
。我将为这个名为 MatrixIterator
.
的迭代器创建一个不同的 class
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);
}
我认为没有人发布过异步迭代器的示例,所以给您:
class TableReadStream<T extends any[]> {
async *[Symbol.asyncIterator]() {
let row: T
while((row = await this.readRow()) !== null) {
yield row
}
}
}
用法:
for await(let row of readStream) {
console.log(row)
}
我如何以与 JS1.7 SomeClass.prototype.__iterator__ = function() {...}
语法相同的方式从 ES6 class 中创建迭代器?
[编辑16:00]
以下作品:
class SomeClass {
constructor() {
}
*[Symbol.iterator]() {
yield '1';
yield '2';
}
//*generator() {
//}
}
an_instance = new SomeClass();
for (let v of an_instance) {
console.log(v);
}
WebStorm 直接在星号之后用 'function name expected' 警告标记 *[Symbol.iterator]()
,但除此之外,它可以通过 Traceur 正常编译和运行。 (注意 WebStorm 不会为 *generator()
生成任何错误。)
您需要为 SomeClass
指定 Symbol.iterator
属性,为 class 实例指定 returns iterator。迭代器必须有 next()
方法, 反过来 returns 对象有 done
和 value
字段。简化示例:
function SomeClass() {
this._data = [1,2,3,4];
}
SomeClass.prototype[Symbol.iterator] = function() {
var index = 0;
var data = this._data;
return {
next: function() {
return { value: data[++index], done: !(index in data) }
}
};
};
或者使用 ES6 classes 和箭头函数:
class SomeClass {
constructor() {
this._data = [1,2,3,4];
}
[Symbol.iterator]() {
var index = -1;
var data = this._data;
return {
next: () => ({ value: data[++index], done: !(index in data) })
};
};
}
和用法:
var obj = new SomeClass();
for (var i of obj) { console.log(i) }
在你更新的问题中,你通过生成器函数实现了class迭代器。你可以这样做,但你必须明白迭代器不能是生成器。实际上 es6 中的迭代器是任何具有特定 next()
method
定义合适的迭代器方法。例如:
class C {
constructor() { this.a = [] }
add(x) { this.a.push(x) }
[Symbol.iterator]() { return this.a.values() }
}
编辑:示例使用:
let c = new C
c.add(1); c.add(2)
for (let i of c) console.log(i)
这是一个在 ES6
中迭代二维矩阵自定义 class 的示例class Matrix {
constructor() {
this.matrix = [[1, 2, 9],
[5, 3, 8],
[4, 6, 7]];
}
*[Symbol.iterator]() {
for (let row of this.matrix) {
for (let cell of row) {
yield cell;
}
}
}
}
这种 class 的用法是
let matrix = new Matrix();
for (let cell of matrix) {
console.log(cell)
}
哪个会输出
1
2
9
5
3
8
4
6
7
实施迭代器协议和可迭代协议技术的示例class:
class MyCollection {
constructor(elements) {
if (!Array.isArray(elements))
throw new Error('Parameter to constructor must be array');
this.elements = elements;
}
// Implement "iterator protocol"
*iterator() {
for (let key in this.elements) {
var value = this.elements[key];
yield value;
}
}
// Implement "iterable protocol"
[Symbol.iterator]() {
return this.iterator();
}
}
使用任一技术访问元素:
var myCollection = new MyCollection(['foo', 'bar', 'bah', 'bat']);
// Access elements of the collection using iterable
for (let element of myCollection)
console.log('element via "iterable": ' + element);
// Access elements of the collection using iterator
var iterator = myCollection.iterator();
while (element = iterator.next().value)
console.log('element via "iterator": ' + element);
存储在子对象中的 ES6 迭代器示例 class:
class Iterator {
data;
constructor(data = {}) {
this.data = JSON.parse(JSON.stringify(data));
}
add(key, value) { this.data[key] = value; }
get(key) { return this.data[key]; }
[Symbol.iterator]() {
const keys = Object.keys(this.data).filter(key =>
this.data.hasOwnProperty(key));
const values = keys.map(key => this.data[key]).values();
return values;
}
}
说明
使一个对象可迭代意味着这个对象有一个以Symbol.iterator
命名的方法。调用此方法时,它应该 return 一个名为 iterator.
这个迭代器必须有一个方法next
,return是下一个结果。这个结果应该是一个对象,带有提供下一个值的 value
属性 和 done
属性,当没有更多时应该是 true
结果和 false
否则。
实施
我还将为一个名为 Matrix
的 class 实现一个迭代器,其中所有元素的范围从 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);
}
我认为没有人发布过异步迭代器的示例,所以给您:
class TableReadStream<T extends any[]> {
async *[Symbol.asyncIterator]() {
let row: T
while((row = await this.readRow()) !== null) {
yield row
}
}
}
用法:
for await(let row of readStream) {
console.log(row)
}