[英]How to make an iterator out of an ES6 class
How would I make an iterator out of an ES6 class in the same manner as JS1.7 SomeClass.prototype.__iterator__ = function() {...}
syntax?我如何以与 JS1.7 SomeClass.prototype.__iterator__ = function() {...}
语法相同的方式从 ES6 类中创建SomeClass.prototype.__iterator__ = function() {...}
?
[EDIT 16:00] [编辑 16:00]
The following works:以下工作:
class SomeClass {
constructor() {
}
*[Symbol.iterator]() {
yield '1';
yield '2';
}
//*generator() {
//}
}
an_instance = new SomeClass();
for (let v of an_instance) {
console.log(v);
}
WebStorm flags *[Symbol.iterator]()
with a 'function name expected' warning directly following the asterix, but otherwise this compiles and runs fine with Traceur. WebStorm 标记*[Symbol.iterator]()
并在星号后直接带有“函数名称预期”警告,但除此之外,它可以编译并与 Traceur 一起正常运行。 (Note WebStorm does not generate any errors for *generator()
.) (注意 WebStorm 不会为*generator()
生成任何错误。)
You need to specify Symbol.iterator
property for SomeClass
which returns iterator for class instances.您需要为SomeClass
指定Symbol.iterator
属性,它返回类实例的迭代器。 Iterator must have next()
method, witch in turn returns object with done
and value
fields.迭代器必须有next()
方法,女巫依次返回带有done
和value
字段的对象。 Simplified example:简化示例:
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) }
}
};
};
Or using ES6 classes and arrow functions:或者使用 ES6 类和箭头函数:
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) })
};
};
}
And usage:和用法:
var obj = new SomeClass();
for (var i of obj) { console.log(i) }
In your updated question you realized class iterator through generator function .在您更新的问题中,您通过生成器函数实现了类迭代器。 You can do so, but you must understand that iterator COULD NOT BE a generator.你可以这样做,但你必须明白迭代器不能是一个生成器。 Actually iterator in es6 is any object that has specific next()
method实际上 es6 中的迭代器是具有特定next()
方法的任何对象
Define a suitable iterator method.定义合适的迭代器方法。 For example:例如:
class C {
constructor() { this.a = [] }
add(x) { this.a.push(x) }
[Symbol.iterator]() { return this.a.values() }
}
Edit: Sample use:编辑:示例使用:
let c = new C
c.add(1); c.add(2)
for (let i of c) console.log(i)
Here's an example for iterating over a 2d matrix custom class in ES6这是在 ES6 中迭代二维矩阵自定义类的示例
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;
}
}
}
}
The usage of such a class would be这样一个类的用法是
let matrix = new Matrix();
for (let cell of matrix) {
console.log(cell)
}
Which would output哪个会输出
1
2
9
5
3
8
4
6
7
Documentation: Iteration Protocols文档: 迭代协议
Example class implementing both iterator protocol and iterable protocol techniques:实现迭代器协议和可迭代协议技术的示例类:
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();
}
}
Access elements using either technique:使用任一技术访问元素:
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);
Making an object iterable means this object has a method named with the Symbol.iterator
.使对象可迭代意味着该对象有一个以Symbol.iterator
命名的方法。 When this method gets called, it should return an interface called iterator .当这个方法被调用时,它应该返回一个名为iterator的接口。
This iterator must have a method next
that returns the next result.这个迭代器必须有一个方法next
返回下一个结果。 This result should be an object with a value
property that provides the next value, and a done
property, which should be true
when there are no more results and false
otherwise.这个结果应该是一个对象,它有一个提供下一个值的value
属性和一个done
属性,当没有更多结果时应该为true
,否则为false
。
I will also implement an iterator for a class called Matrix
which all elements will range from 0
to width * height - 1
.我还将为一个名为Matrix
的类实现一个迭代器,其中所有元素的范围都从0
到width * height - 1
。 I will create a different class for this iterator called MatrixIterator
.我将为这个迭代器创建一个不同的类,称为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};
}
}
Notice that Matrix
implements the iterator protocol by defining Symbol.iterator
symbol.请注意, Matrix
通过定义Symbol.iterator
符号来实现迭代器协议。 Inside this method, an instance of MatrixIterator
is created which takes this
, ie, the Matrix
instance as parameter, and inside MatrixIterator
, the method next
is defined.在这个方法中,创建了一个MatrixIterator
的实例,它以this
为参数,即Matrix
实例作为参数,在MatrixIterator
,定义了next
方法。 I particularly like this way of implementing an iterator because it clearly shows the iterator and the implementation of the Symbol.iterator
.我特别喜欢这种实现迭代器的方式,因为它清楚地展示了迭代器和Symbol.iterator
的实现。
Alternatively, one can also not define directly Symbol.iterator
, and instead add a function to prototype[Symbol.iterator]
as follows:或者,也可以不直接定义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);
}
Example of an ES6 iterator class that stores in a sub-object:存储在子对象中的 ES6 迭代器类示例:
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;
}
}
I don't think anyone's posted an example of an async iterator, so here you go:我认为没有人发布过异步迭代器的例子,所以你去吧:
class TableReadStream<T extends any[]> {
async *[Symbol.asyncIterator]() {
let row: T
while((row = await this.readRow()) !== null) {
yield row
}
}
}
Usage:用法:
for await(let row of readStream) {
console.log(row)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.