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)