Back to JavaScript
2026-02-135 min read

Iterators

Learn Iterators step by step with clear examples and exercises.

Why This Matters

Iterators are an essential part of JavaScript programming, providing a powerful tool for traversing collections like arrays, strings, and more. In this article, we will delve deeper into understanding iterators, their importance, and how to use them effectively in various scenarios.

The Importance of Iterators

Iterators simplify the process of looping through elements in a collection, making your code more readable and efficient. They help solve real-world problems, prepare you for coding interviews, and even aid in debugging common issues during development.

Prerequisites

Before diving into iterators, it's crucial to have a good understanding of the following concepts:

  1. Variables and data types in JavaScript
  2. Control structures such as for loops and conditional statements
  3. Functions and function declarations
  4. Arrays and array methods like map, filter, and reduce
  5. Promises for handling asynchronous operations (optional but recommended)

Core Concept

Iterator Interface

An iterator is an object that follows a specific protocol, allowing it to be traversed sequentially. This protocol includes a next() method that returns an object with two properties: value and done. The value property contains the next item in the sequence, while done indicates whether the iteration has reached the end or not.

Here's a simple example of creating a custom iterator for an array:

let myArray = [1, 2, 3];
let myIterator = {
current: 0,
last: myArray.length - 1,
next() {
if (this.current <= this.last) {
return { value: myArray[this.current++], done: false };
} else {
return { done: true };
}
},
};

In the above example, we've created a custom iterator for an array called myArray. The next() method checks if the current index is less than or equal to the last index. If so, it returns the current value and moves to the next index. Once the end of the array is reached, it returns { done: true }, indicating that there are no more values to iterate over.

Built-in Iterators

JavaScript provides built-in iterators for several data structures, such as arrays, strings, and maps. These iterators follow the iterator protocol, making them easy to use with loops like for...of.

Here's an example of using the built-in array iterator:

let numbers = [1, 2, 3];
for (let number of numbers) {
console.log(number);
}

In this example, we've used the for...of loop to iterate through an array called numbers. The built-in iterator handles the traversal for us, and we can simply access each element in the array as number.

Iterator Methods on Built-in Objects

Built-in objects like arrays, strings, and maps also provide additional methods that work with iterators. For example:

  1. Array's forEach() method: Applies a provided function to each element in the array.
  2. String's split() method: Splits a string into an array of substrings based on a specified delimiter.
  3. Map's keys(), values(), and entries() methods: Return iterable objects that can be used with for...of loops to traverse the map.

Worked Example

Let's create a simple application that fetches data from an API, processes it using built-in array methods, and displays the results using iterators.

// Fetch data from an API
async function fetchData() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos');
const data = await response.json();
return data;
}

// Filter out todos with completed status (status: 1)
function filterCompletedTodos(todos) {
return todos.filter(todo => todo.completed === 1);
}

// Create an iterator for the filtered todos
function createTodoIterator(todos) {
let index = 0;
return {
next() {
if (index < todos.length) {
return { value: todos[index++], done: false };
} else {
return { done: true };
}
},
};
}

// Fetch and display the filtered todos using the iterator
async function displayCompletedTodos() {
const data = await fetchData();
const completedTodos = filterCompletedTodos(data);
const iterator = createTodoIterator(completedTodos);

for (let todo of iterator) {
console.log(todo);
}
}

displayCompletedTodos();

In this example, we've created an asynchronous function fetchData() that fetches data from a mock API and returns it as an array. We then use the built-in filter() method to filter out todos with completed status (status: 1). Finally, we create an iterator for the filtered todos using the createTodoIterator() function. The for...of loop is used to iterate through the data and display each completed todo item.

Common Mistakes

  1. Forgetting to return the object in the next() method: If you forget to return the object from the next() method, your iterator will not work as expected.
  2. Iterating over an empty collection: Always check if a collection is empty before iterating over it, or handle the case where the iteration might result in an empty sequence.
  3. Misusing iterators with non-iterable objects: Iterators are designed for collections like arrays and maps. Using them with non-iterable objects can lead to unexpected results.
  4. Confusing iterators with generators: While related, iterators and generators have different purposes and behaviors. Make sure you understand the differences between the two.
  5. Not handling the case where the next() method throws an error: If an error occurs during iteration, it can cause the entire loop to fail. It's essential to handle errors appropriately within the next() method or when using iterators in loops.

Practice Questions

  1. Write a custom iterator for a string that returns each character in reverse order.
  2. Given an array of objects, write a function that creates an iterator that filters out any object with a property named isDone and sets its value to false.
  3. Implement a simple application that fetches data from multiple APIs, processes the data using iterators and built-in array methods, and displays the results.
  4. Create a custom iterator for a linked list data structure.
  5. Write a function that takes an array of numbers and returns an iterator that generates the Fibonacci sequence up to the last number in the input array.

FAQ

  1. What happens when done is true in the next() method?: When done is set to true, the iteration is complete, and no more values will be returned.
  2. Can I create an iterator for a custom object?: Yes, you can create an iterator for any object that follows the iterator protocol, which includes having a next() method that returns an object with value and done properties.
  3. What is the difference between iterators and generators in JavaScript?: Iterators are objects that follow a specific protocol to allow traversal of collections sequentially, while generators are functions that can be paused and resumed, making them useful for generating infinite sequences or handling asynchronous operations.
  4. How do I create an iterator for a linked list data structure?: To create an iterator for a linked list, you'll need to maintain a current node and implement the next() method to return the next node in the list until there are no more nodes left.
  5. Can I use iterators with Promises?: Yes, you can use iterators with Promises by wrapping asynchronous operations within a Promise and returning it from the next() method. The iterator will automatically handle the resolution or rejection of the Promise.
Iterators | JavaScript | XQA Learn