ES6 Everyday: for..of Loops and the Iterable Protocol

Remember yesterday when we learned about this weird new data type called symbols?

We’re going to use that knowledge today.

Along with a bounty of new features, ES6 also defines a “protocol,” called the iterable protocol. Objects that adhere to this protocol are considered “iterable.”

To adhere to this protocol, an object must implement the ”@@iterator” method, which means that the object must have a method that loops through a set of elements, returning one at a time.

Furthermore, in yesterday’s post we discussed how symbols can be used as a key to reference a type of function across different implementations.

Similarly, the last piece of implementing @@iterator is having a property on your object that references your looping method with a “well-known” symbol, called Symbol.iterator.

That was a lot at once, so let’s back up and piece this all together.

There’s a “well-known” symbol out there called “iterator” that is globally defined as a property on the Symbol class:

console.log(Symbol.iterator.toString()) // Symbol(Symbol.iterator)

To fully implement the @@iterator method, our object must use Symbol.iterator as a key to reference our looping method described above:

iterableObject[Symbol.iterator] = function() { /* ...looping logic */ };

Wow, so who would bother going through all of this trouble? Well, in fact, many of the built-in classes within ES6 would:

var testString = new String();
// function [Symbol.iterator]() { [native code] }

var testArray = new Array();
// function ArrayValues() { [native code] }

Okay, so that’s nice and all, but what’s the point of going through all of this trouble?

If @@iterator is implemented then a new type of loop, for..of, can be used. for..of allows us to loop over the values of an iterable object.

With strings:

var greeting = "Hello";

for(let letter of greeting)
  console.log(letter); // H, e, l, l, o

And arrays:

var fruits = ["Apple", "Strawberry", "Orange"];

for(let item of fruits)
  console.log(item); // Apple, Strawberry, Orange

This may seem vaguely familiar to you, but it’s likely you’re thinking of the construct, which loops over property names:

var person = {
  firstName: 'Logan',
  lastName: 'Franken',
  age: 27

for(let propName in person)
  console.log(propName); // firstName, lastName, age

So, if we used it on an array:

var fruits = ["Apple", "Strawberry", "Orange"];

for(let item in fruits)
  console.log(item); // 0, 1, 2