Iterables and Iterators in JavaScript

Iterables and Iterators in JavaScript

Iterables and Iterators in JavaScript

  • Iterator is an object which implements the iteration protocol.
  • We have two iteration protocols
    1. The iterator protocol
    2. The iterable protocol

The iterator protocol

  • The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite), and potentially a return value when all values have been generated.
  • next() - A function, with either zero arguments or one argument, that returns object with properties done and value
  • done - boolean which represents whether next value available or not.
  • value - Any JavaScript value returned by the iterator.
  • Let's see an example, how we can implement it.
const generateFibonacciIterator = (max=Infinity) => {
  let n1 = 0;
  let n2 = 0;
  return {
    next: () => {
      let nextVal = n2 === 0 ? 1 : n1 + n2;

      // update n1, n2
      const prevVal = n2;
      n2 = nextVal;
      n1 = prevVal;

      // set {done, value}
      let done = false
      if (nextVal >= max) {
        nextVal = undefined
        done = true
      }

      // return iteration object
      return {done, value: nextVal}
    }
  }
}

// create iterator
const iterator = generateFibonacciIterator(5);
// now use `next()` method to get the value.
console.log(iterator.next());
// output: {done: false, value: 1}
console.log(iterator.next());
// output: {done: false, value: 1}
console.log(iterator.next());
// output: {done: false, value: 2}
console.log(iterator.next());
// output: {done: false, value: 3}
console.log(iterator.next());
// output: {done: true, value: undefined}

Note: we can't use it with the spread ... operator or for...of constructor.

The iterable protocol

  • The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for...of construct.
  • String, Array, TypedArray, Map, and Set are all built-in iterables
  • Let's see an example, how we can implement it.
const myNumbersIterator = {
  begin: 1,
  end: 3,

  // iterator built-in to work with spread `...` operator
  [Symbol.iterator](){
    this.current = this.begin;
    return this;
  },

  next(){
    if (this.current <= this.end) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true, value: undefined };
    }
  }
}
  • Now, we can use above iterator with for...of construct like below.
for(const num of myNumbersIterator){
  console.log(num);
}
/**
1
2
3
*/

// spread operator
console.log(myNumbersIterator)
// 1 2 3

Note: Symbol.iterator must be implemented to work with constructs like for...of, ..., etc.

References: