Creating custom Iterable by implementing Symbol.iterator method

Question | Feb 11, 2016 | hkumar 

JavaScript iterators are almost always discussed with generators. These two ES6 concepts are very much related to each other but IMHO iterators deserve their own separate space during introduction. In order to grasp the concept of iterators you need to know the difference between iterator and iterable.

Iterator
An iterator is an object that implements next() method. The iterator next() method returns an object that can have 2 properties, value and done, e.g { value: 4, done: false }. The caller of next() can keep calling it for next value until done is false.

Iterable
An iterable is an object (it could be an array or string) that implements an @@iterable method, which in turn returns an iterator. An @@iterable method is nothing but a function bound to Symbol.iterator property of an object. Clients of an iterable call its @@iterator method to get an iterator.

The most convincing use of iterator is in for...of loop. Let's look at an example. Suppose we have a stock_prices object that has a list of historical close prices for past few days along with other properties. We want to provide an interface to clients of stock_prices so they can iterate over closing prices using for...of loop. This is how we make stock_prices an iterable:

var stock_prices = { 
  ticker: 'IBM',
  country: 'USA',
  closePrices: [ 170.4, 171.6, 173.2, 169.12 ]   
};

// @@Iterator Method. 
// This would make stock_prices an iterable. 
stock_prices[Symbol.iterator] = function() {

 var self = this;
 var priceIndex = 0;

 // @@Iterator returns an iterator object
 return { 
   // iterator object must implement next method
    next: function() {
         return priceIndex < self.closePrices.length ?
           { value: self.closePrices[priceIndex++], done: false } :
           { done: true };
    }
 };
};

// Iterate over prices.
for(let p of stock_prices)
{
   console.log(stock_prices.ticker+':'+p)
}

Cool! Right? Some JavaScript built-in types are built-in iterables namely Array, Map, Set, string. Let's have some fun by changing the default @@iterable method of an array. Look at below code and answer the following question. Trust me, you can do this!

var array = [ 2, 3, 4 ];
array[Symbol.iterator] = function() {  

 var index = 0;    
 return { 
    next: function() {
         return index < array.length ?
           { value: array[index]*array[index++], done: false } :
           { done: true };
    }
  };
};

var sum = 0;
for(let v of array)
{
  sum += v;
}

What will be the value of sum?