Search code examples
javascriptiterator

How to make custom iterator interface iterable in JavaScript


I have an array, and i have overridden its default Iterator behavior. The problem is that, after overriding, the returned iterator becomes non iterable and for..of..loop fails on it but works on the array, but explicit call on the array's iterator next() method still works. Here is the code below:

let arr = ["A", "B", "C", "D", "E", "F"];
arr[Symbol.iterator] = function(){
  let i = 0;

  return {
    //Iterator interface
    next:function(){
      //IteratorResult Interface
      return {
        value: arr[i++]+"..",
        done: arr[i] == undefined?true:false
      }
    }
  }
}

And here is the iterator object

let arrIterator = arr[Symbol.iterator](); //An iterator object returned but not iterable

Consumption trial with for..of..loop on iterator object

for (let i of arrIterator){
  console.log(i);
}

OUTPUT

for..of..loop trial on iterator result

Consumption trial with for..of..loop on array

for (let i of arr){
  console.log(i);
}

OUTPUT

for..of..loop trial on array result

Consumption trial with explicit next() method call

console.log(arrIterator.next());
console.log(arrIterator.next());
console.log(arrIterator.next());
console.log(arrIterator.next());
console.log(arrIterator.next());
console.log(arrIterator.next());
console.log(arrIterator.next());
console.log(arrIterator.next());

OUTPUT

explicit next() method call on iterator result

Please i really want to know how to make the custom iterator iterable for for..of..loop consumption.

Thanks


Solution

  • You need to implement the Iterable protocol as well (instead of just the Iterator)

    Add [Symbol.iterator]: function() { return this; } to your Iterator object and it will work.

    let arr = ["A", "B", "C", "D", "E", "F"];
    arr[Symbol.iterator] = function() {
      let i = 0;
    
      return {
        //Iterator interface
        next: function() {
          //IteratorResult Interface
          return {
            value: arr[i++] + "..",
            done: arr[i] == undefined ? true : false
          }
        },
        // Iterable interface
        [Symbol.iterator]: function() {
          return this;
        }
      }
    }
    
    let arrIterator = arr[Symbol.iterator](); //An iterator object returned but not iterable
    
    for (let i of arrIterator) {
      console.log(i);
    }

    See Iteration protocols for more info