DEV Community

Dharan Ganesan
Dharan Ganesan

Posted on

Day 21: Iterators

🤔 What are Iterators?

Iterators allow us to loop through data one element at a time. They provide a standardized way to access elements in a collection, such as arrays or maps, without exposing the underlying implementation details.

📜 The Iterator Protocol

Before ES6 (ECMAScript 2015), iterating over data structures in JavaScript was mainly done using for loops. However, with the introduction of the Iterator Protocol, a cleaner and more versatile approach emerged.

The Iterator Protocol consists of two essential components:

  1. Iterable: An object that has an iterator method. This method returns an Iterator object, allowing us to traverse through the collection.

  2. Iterator: An object that implements the next() method. This method returns an object with two properties: value, which represents the current element, and done, a boolean indicating whether the iteration is complete.

🛠️ Using Iterators

🔄 The for...of Loop

The for...of loop is a handy feature that emerged with ES6, making it easier to work with iterators. Let's see how it works with an array:

const fruits = ['🍎', '🍌', '🍇', '🍊', '🍓'];

for (const fruit of fruits) {
  console.log(fruit);
}
Enter fullscreen mode Exit fullscreen mode

Here, the for...of loop automatically handles the iteration process using the iterator of the fruits array.

🎨 Creating Custom Iterators

We can also define custom iterators for our own objects. To do that, we need to implement the iterator protocol on our object.

const range = {
  start: 1,
  end: 5,
  [Symbol.iterator]() {
    let currentValue = this.start;
    return {
      next: () => {
        if (currentValue <= this.end) {
          return { value: currentValue++, done: false };
        } else {
          return { done: true };
        }
      },
    };
  },
};

for (const num of range) {
  console.log(num);
}
Enter fullscreen mode Exit fullscreen mode

This code will output the numbers from 1 to 5, demonstrating how we can define custom iteration behavior.

Built-in Iterators 🛠️

JavaScript provides several built-in data structures that are iterable, including arrays, strings, maps, sets, and more. We can use these structures with the for...of loop or any other iterator-consuming method.

🔤 Iterating Over a String

const message = "Hello, Dev.to! 🚀";

for (const char of message) {
  console.log(char);
}
Enter fullscreen mode Exit fullscreen mode

🗺️ Iterating Over a Map

const myMap = new Map([
  ['key1', 'value1'],
  ['key2', 'value2'],
  ['key3', 'value3'],
]);

for (const [key, value] of myMap) {
  console.log(`${key} => ${value}`);
}
Enter fullscreen mode Exit fullscreen mode

✨ Advantages of Using Iterators

  • Custom Iteration Behavior: With iterators, you can define custom iteration behavior for your objects. This flexibility allows you to loop through data structures in a way that makes the most sense for your specific use case.
  • Asynchronous Iteration: ES6 introduced asynchronous iterators (Symbol.asyncIterator), which are invaluable when dealing with asynchronous operations and streams. They enable elegant handling of async data.
  • Lazy Evaluation: Iterators facilitate lazy evaluation, where the next value is generated only when needed. This can be especially helpful when dealing with large data sets, as it minimizes memory consumption.
  • Generators: Generators are a special type of iterator that allows you to pause and resume the execution of a function. They are handy for creating iterators with complex logic in a more readable and maintainable way.

Top comments (0)