JavaScript for impatient programmers (beta)
Please support this book: buy it or donate
(Ad, please don’t block.)

27. Synchronous iteration



27.1. What is synchronous iteration about?

Synchronous iteration is a protocol (interfaces plus rules for using them) that connects two groups of entities in JavaScript:

The iteration protocol connects these two groups via the interface Iterable: data sources deliver their contents sequentially “through it”; data consumers get their input via it.

Figure 26: Data consumers such as the for-of loop use the interface Iterable. Data sources such as Arrays implement that interface.
Figure 26: Data consumers such as the for-of loop use the interface Iterable. Data sources such as Arrays implement that interface.

The diagram in fig. 26 illustrates how iteration works: data consumers use the interface Iterable; data sources implement it. Note that in JavaScript, implementing only means having the methods described by the interface; the interface itself only exists in the specification.

Both sources and consumers of data profit from this arrangement:

27.2. Core iteration constructs: iterables and iterators

Two roles (described by interfaces) form the core of iteration (fig. 27):

Figure 27: Iteration has two main interfaces: Iterable and Iterator. The former has a method that returns the latter.
Figure 27: Iteration has two main interfaces: Iterable and Iterator. The former has a method that returns the latter.

These are type definitions (in TypeScript’s notation) for the interfaces of the iteration protocol:

interface Iterable<T> {
  [Symbol.iterator]() : Iterator<T>;
}

interface Iterator<T> {
  next() : IteratorResult<T>;
}

interface IteratorResult<T> {
  value: T;
  done: boolean;
}

The interfaces are used as follows:

27.3. Iterating manually

This is an example of using the iteration protocol:

const iterable = ['a', 'b'];

// The iterable is a factory for iterators:
const iterator = iterable[Symbol.iterator]();

// Call .next() until .done is true:
assert.deepEqual(
  iterator.next(), { value: 'a', done: false });
assert.deepEqual(
  iterator.next(), { value: 'b', done: false });
assert.deepEqual(
  iterator.next(), { value: undefined, done: true });

27.3.1. Iterating over an iterable via while

The following code demonstrates how to use a while loop to iterate over an iterable:

function logAll(iterable) {
  const iterator = iterable[Symbol.iterator]();
  while (true) {
    const {value, done} = iterator.next();
    if (done) break;
    console.log(value);
  }
}

logAll(['a', 'b']);
// Output:
// 'a'
// 'b'

  Exercise: Using sync iteration manually

exercises/sync-iteration/sync_iteration_manually_exrc.js

27.4. Iteration in practice

We have seen how to use the iteration protocol manually and it is relatively cumbersome. But the protocol is not meant to be used directly – it is meant to be used via higher-level language constructs built on top of it. This section shows what that looks like.

27.4.1. Arrays

JavaScript’s Arrays are iterable. That enables you to use the for-of loop:

const myArray = ['a', 'b', 'c'];

for (const x of myArray) {
  console.log(x);
}
// Output:
// 'a'
// 'b'
// 'c'

Destructuring via Array patterns (explained later) also uses iteration, under the hood:

const [first, second] = myArray;
assert.equal(first, 'a');
assert.equal(second, 'b');

27.4.2. Sets

JavaScript’s Set data structure is iterable. That means, for-of works:

const mySet = new Set().add('a').add('b').add('c');

for (const x of mySet) {
  console.log(x);
}
// Output:
// 'a'
// 'b'
// 'c'

As does Array-destructuring:

const [first, second] = mySet;
assert.equal(first, 'a');
assert.equal(second, 'b');

27.5. Quick reference: synchronous iteration

27.5.1. Iterable data sources

The following built-in data sources are iterable:

To iterate over the properties of objects, you need helpers such as Object.keys() and Object.entries(). That is necessary, because properties exist at a different level that is complementary to the level of data structures.

27.5.2. Iterating constructs

The following constructs support iteration:

27.6. Further reading

For more details on synchronous iteration, consult “Exploring ES6”.

  Quiz

See quiz app.