Reputation: 639
I'm trying to figure out how to add an itertor to a javascript class such that the class could be used in a for...in loop. Following the instructions from Mozilla doesn't produce the results they claim it will. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators Jsfiddle of given example: http://jsfiddle.net/KQayW/
function Range(low, high){
this.low = low;
this.high = high;
this.current = low;
this.next = function() {
if (this.current > this.range.high)
throw StopIteration;
else
return this.current++;
}
}
function RangeIterator(range){
this.range = range;
this.current = this.range.low;
}
RangeIterator.prototype.next = function(){
if (this.current > this.range.high)
throw StopIteration;
else
return this.current++;
};
Range.prototype.__iterator__ = function(){
return new RangeIterator(this);
};
var range = new Range(3, 5);
for (var i in range)
document.getElementById("test").innerHTML = i+"</br>"; // prints 3, then 4, then 5 in sequence
It doesn't print out the numbers in the range, it prints out "__iterator__"!
Does anyone know how to get this to work?
Upvotes: 11
Views: 8342
Reputation: 350310
With ES2025 we can chain iterator helper methods:
const Range = (start, end) => Array(end - start).keys().map(x => x + start)
for (const x of Range(1, 10)) {
console.log(x)
}
Although an Array instance is created, it is one that remains "empty", i.e. it doesn't allocate index slots and so it takes constant space, irrespective of the argument given. The keys
method returns an iterator, and map
is an iterator method (not an array method) that returns the desired iterator.
Upvotes: 0
Reputation: 6113
Or you can do it without the generator syntax. This may help if you are trying to understand how iterators work.
function range(start, end) {
return {
[Symbol.iterator]() {
return this;
},
next() {
return start <= end ? {value: start++} : {done: true};
}
};
}
console.log(...range(1, 10));
The range()
function returns an 'iterable object'.
The iterable object is iterable because it has a function [Symbol.iterator]()
that returns an 'iterator object'.
The iterator object is an iterator because it has a next()
function.
In this case the iterable and the iterator are the same object, which simplifies it.
Upvotes: 2
Reputation: 7438
With ES2015 it can be even more simple
const Range = (start, end) => ({
*[Symbol.iterator]() {
while (start < end)
yield start++;
}
})
for (var x of Range(1, 10)) {
console.log(x)
}
Upvotes: 10
Reputation: 580
With ES2015 its simple:
function Range(start, end) {
var ret = {};
ret[Symbol.iterator] = function *() {
while (start < end)
yield start++;
}
return ret;
}
Though you have to use:
for (var x of Range(1, 10))
Upvotes: 9
Reputation: 99
The Mozilla document state that the Iterators feature was introduced in JavaScript 1.7. Although Chrome supports some features from 1.7, it isn't fully supported so this does not work. If you test your code in the latest Firefox version though you will see it works.
Although you probably want to append the range value rather than replacing the entire div.
function Range(low, high){
this.low = low;
this.high = high;
this.current = low;
this.next = function() {
if (this.current > this.range.high)
throw StopIteration;
else
return this.current++;
}
}
function RangeIterator(range){
this.range = range;
this.current = this.range.low;
}
RangeIterator.prototype.next = function(){
if (this.current > this.range.high)
throw StopIteration;
else
return this.current++;
};
Range.prototype.__iterator__ = function(){
return new RangeIterator(this);
};
var range = new Range(3, 5);
for (var i in range)
document.getElementById("test").innerHTML += i+"</br>"; // prints 3, then 4, then 5 in sequence
Upvotes: 3