Skip to main content

JavaScript Generators & Iterators

JavaScript Iterables

Written by Published

An iterable is anything with a Symbol.iterator method, which is what for...of actually looks for.

An iterable is anything with a Symbol.iterator method, which is what for of actually looks for.

Iterable and iterator sound alike but mean different things.

An iterable knows how to produce an iterator; the iterator does the actual work.

Example

Example

javascript

const numbers = [1, 2, 3];

console.log(typeof numbers[Symbol.iterator]);

for (const n of numbers) {
  console.log(n);
}

for of calls that method behind the scenes.

Iterable Versus Iterator

An iterable has a [Symbol.iterator]() method.

Calling that method returns an iterator.

for of, spread and destructuring all rely on this.

Syntax

Syntax

javascript

for (const value of iterable) {
  // one value per turn
}

Anything without Symbol.iterator cannot be used here.

What Counts as Iterable

Arrays, strings, Maps and Sets all qualify.

Example

Example

javascript

console.log(typeof [][Symbol.iterator]);
console.log(typeof "text"[Symbol.iterator]);
console.log(typeof new Map()[Symbol.iterator]);
console.log(typeof new Set()[Symbol.iterator]);

All four report function.

Plain Objects Are Not Iterable

This is exactly why for of throws on one.

Example

Example

javascript

const settings = { theme: "dark" };
let message;

try {
  for (const value of settings) {
    message = "looped";
  }
} catch (error) {
  message = error.name;
}

console.log(message);

The output is TypeError.

Spread Needs Iterable Too

Spreading an object into an array fails for the same reason.

Example

Example

javascript

const numbers = [1, 2, 3];
console.log([...numbers].length);

let message;
try {
  [...{ a: 1 }];
} catch (error) {
  message = error.name;
}
console.log(message);

Spreading an array works; spreading a plain object as a list does not.

Destructuring Also Relies on It

Array destructuring is short for calling the iterator repeatedly.

Example

Example

javascript

const colours = ["red", "green", "blue"];

const [first, second] = colours;

console.log(first + " " + second);

Object destructuring works differently and does not need this protocol.

Object Spread Is a Different Feature

Spreading a plain object with { ...obj } copies properties, unrelated to iteration.

It is easy to mix the two up, since both use three dots.

Example

Example

javascript

const settings = { theme: "dark" };
const copy = { ...settings };

console.log(copy.theme);

This works because object spread has its own separate rule, not the iterable protocol.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Iterables</title>
</head>
<body>

  <h1>Iterables</h1>

  <p id="out"></p>

  <script>
    const values = new Set([1, 2, 3]);
    const list = [];

    for (const value of values) {
      list.push(value);
    }

    document.getElementById("out").textContent =
      "From a Set: " + list.join(", ");
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try a Map:

Loop over new Map([["a", 1]]) and see each entry arrive as a pair.

Important Points

  • An iterable has a Symbol.iterator method.
  • Arrays, strings, Maps and Sets are all iterable.
  • Plain objects are not, so for of throws on one.
  • Spread and destructuring both rely on being iterable.
  • Object spread with { ...obj } is a separate feature.

Conclusion

Being iterable is what unlocks for of, spread and destructuring.

Plain objects opt out, which is a deliberate design choice, not an oversight.

The next lessons show how to make your own values iterable.