Kevin Hallett

moon indicating dark mode
sun indicating light mode

JavaScript Iterables - A Guide to Mastering ES6 Protocols for Iteration

October 23, 2019

Understanding JavaScript Iterables: A Key ES6 Feature

When ES6 (ECMAScript 2015) was introduced, JavaScript developers were given new tools to work with data structures more flexibly. Two of these tools are the iterable and iterator protocols, which together make JavaScript’s iteration behavior more powerful and extensible.

Some JavaScript objects, like Array and Map, are already “iterable,” meaning they come with built-in behavior that allows you to loop over them using constructs like the for..of loop. But one of the most powerful features of ES6 is that you can define this iterable behavior for your custom objects as well. In this guide, we’ll explore exactly how to implement iterable behavior, making your JavaScript code more efficient and expressive.


Key Concepts

Understanding the two main concepts, iterable and iterator, is essential:

  • Iterable: Any object that implements a Symbol.iterator method, which returns an iterator.
  • Iterator: Any object that implements a next method, which returns a result object containing value and done properties.

This architecture allows you to customize how JavaScript structures, like objects, are accessed in a loop, helping you manage both the iteration logic and the data access.


Making an Object Iterable: Step-by-Step Guide

To get a practical feel for iterables, let’s imagine a scenario where you have a plain JavaScript object that holds user information, keyed by user ID. We want to iterate over this object to access each user’s data. If we attempt to use a for..of loop directly on the object, however, we get an error, as JavaScript objects are not iterable by default.

Here’s our object structure:

const users = {
1438: {
name: 'Steve'
},
1693: {
name: 'John'
},
2356: {
name: 'Sally'
}
};

Why Use Iterables?

Iterables simplify working with data structures and allow for flexible code reuse in common tasks such as looping, spreading, and destructuring. Without iterables, you’d need to manually extract the object’s keys, retrieve each user, and process them one by one. Let’s make our users object iterable by adding a Symbol.iterator method.


Step-by-Step: Defining an Iterable

Here’s how we define an iterable on the users object:

const users = {
1438: {
name: 'Steve'
},
1693: {
name: 'John'
},
2356: {
name: 'Sally'
},
// Adding Symbol.iterator to make 'users' iterable
[Symbol.iterator]: function() {
let i = 0;
const userIds = Object.keys(users);
return {
next: () => {
if (i >= userIds.length) {
return { done: true }; // Signals the end of iteration
}
const userId = userIds[i];
const user = this[userId];
i++;
return { value: user, done: false };
}
};
}
};

Explanation

  1. Define the Iterator: The Symbol.iterator method returns an object (iterator) with a next method.
  2. Control Iteration: next keeps track of the index i, iterating over the userIds array.
  3. Return Format: The next method returns an object with two properties:
    • value: the current user object.
    • done: a Boolean indicating if the iteration is complete.

Using the Custom Iterable

With this iterator defined, we can now use a for..of loop to easily access each user object:

for (const user of users) {
console.log(user.name);
/**
* Output:
* Steve
* John
* Sally
*/
}

Expanding Iterable Use Cases

In addition to for..of, iterables allow other powerful operations:

// Spread into an array
const userArray = [...users];
console.log(userArray);
// Output: [{name: "Steve"}, {name: "John"}, {name: "Sally"}]

This code allows you to leverage the full potential of JavaScript iterables for flexible and cleaner code when accessing data structures.


Final Thoughts

By defining iterable behavior on custom objects, you can streamline how data structures are accessed and manipulated in JavaScript. This flexibility enables powerful abstractions and greater control over data handling, making you a more effective and versatile JavaScript developer. Leveraging iterables enhances your code quality, allowing for cleaner, more efficient, and reusable functions across your codebase.

Iterables represent just one of many ways ES6 empowers developers with robust tools. Use them in your projects to make your code more modular and improve its readability, especially when working with complex data structures.

Happy coding!



Kevin Hallett
Personal blog by Kevin Hallett.