admin管理员组文章数量:1134577
How would I make an iterator out of an ES6 class in the same manner as JS1.7 SomeClass.prototype.__iterator__ = function() {...}
syntax?
[EDIT 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. (Note WebStorm does not generate any errors for *generator()
.)
How would I make an iterator out of an ES6 class in the same manner as JS1.7 SomeClass.prototype.__iterator__ = function() {...}
syntax?
[EDIT 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. (Note WebStorm does not generate any errors for *generator()
.)
7 Answers
Reset to default 77You need to specify Symbol.iterator
property for SomeClass
which returns iterator for class instances. Iterator must have next()
method, witch in turn returns object with done
and value
fields. 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:
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
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
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);
Explanation
Making an object iterable means this object has a method named with the Symbol.iterator
. When this method gets called, it should return an interface called iterator.
This iterator must have a method next
that returns the next result. 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.
Implementation
I will also implement an iterator for a class called Matrix
which all elements will range from 0
to width * height - 1
. I will create a different class for this iterator called 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. Inside this method, an instance of MatrixIterator
is created which takes this
, i.e., the Matrix
instance as parameter, and inside MatrixIterator
, the method next
is defined. I particularly like this way of implementing an iterator because it clearly shows the iterator and the implementation of the Symbol.iterator
.
Alternatively, one can also not define directly Symbol.iterator
, and instead add a function to prototype[Symbol.iterator]
as follows:
Matrix.prototype[Symbol.iterator] = function() {
return new MatrixIterator(this);
};
Usage Example
let matrix = new Matrix(3, 2);
for (let e of matrix) {
console.log(e);
}
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)
}
Example of an ES6 iterator class that stores in a sub-object:
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;
}
}
本文标签: javascriptHow to make an iterator out of an ES6 classStack Overflow
版权声明:本文标题:javascript - How to make an iterator out of an ES6 class - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736859811a1955865.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
v8.1.1
– Shaheen Ghiassy Commented Jun 23, 2017 at 7:58