Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a custom iterator to a javascript class

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?

like image 577
anonymouse Avatar asked Oct 08 '13 19:10

anonymouse


People also ask

How do you make an object iterable in JavaScript?

To make the range object iterable (and thus let for..of work) we need to add a method to the object named Symbol. iterator (a special built-in symbol just for that). When for..of starts, it calls that method once (or errors if not found). The method must return an iterator – an object with the method next .

What is the difference between iterator and iterable in JavaScript?

Source: A value is considered iterable if it has a method whose key is the symbol Symbol. iterator that returns a so-called iterator. The iterator is an object that returns values via its method next() . We say: it iterates over the items (the content) of the iterable, one per method call.


2 Answers

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))
like image 126
marc meyer Avatar answered Sep 22 '22 19:09

marc meyer


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)
}
like image 41
Krzysztof Safjanowski Avatar answered Sep 23 '22 19:09

Krzysztof Safjanowski