JavaScript Iterators
In JavaScript, iterators are objects that allow you to iterate over a sequence of elements. They are fundamental in loops and JavaScript’s design. This guide will help you understand how iterators work in JavaScript and how to create custom ones. Let's dive deep into JavaScript iterators!
What Are Iterators?
An iterator is a special object in JavaScript that helps you go through a list or collection one item at a time. It has a method called next() which gives you the next item in the sequence.
When you call next(), it returns an object with two important properties:
- value: This is the current item in the list that the iterator returns.
- done: This is a true or false value that tells you if you have reached the end of the list. When done is true, there are no more items left to go through.
Using iterators lets you access each item step-by-step without needing to know how the list or collection is stored inside. This makes it easier and cleaner to work with different types of data.
Iterators vs Iterable
In JavaScript, an iterable is any object that has an [Symbol.iterator] method. Arrays, strings, and maps are common examples of iterables. An iterator, on the other hand, is an object that returns the next item in the sequence when the next() method is called.
The difference is:
- Iterable: An object that implements the [Symbol.iterator] method and can return an iterator.
- Iterator: An object that implements the next() method and returns an object containing value and done.
Example of Iterable:
An array is an example of an iterable:
const myArray = [1, 2, 3, 4];
for (let item of myArray) {
console.log(item);
}
const myArray = [1, 2, 3, 4];
for (let item of myArray) {
console.log(item);
}
Example of Iterator:
An iterator allows you to manually iterate over a sequence using the next() function:
const myIterator = myArray[Symbol.iterator]();
console.log(myIterator.next()); // { value: 1, done: false }
console.log(myIterator.next()); // { value: 2, done: false }
const myIterator = myArray[Symbol.iterator]();
console.log(myIterator.next()); // { value: 1, done: false }
console.log(myIterator.next()); // { value: 2, done: false }
Understanding Built-in Iterators
JavaScript provides several built-in iterators that make it easy to loop through different data structures like arrays, sets, strings, and maps. These iterators allow you to go through each element one by one, without worrying about how the data is stored internally. Let's explore how they work.
The basic structure for using an iterator looks like this:
let iterator = collection[Symbol.iterator]();
let result = iterator.next();
console.log("First result:", result.value, "done:", result.done);
result = iterator.next();
console.log("Second result:", result.value, "done:", result.done);
result = iterator.next();
console.log("Third result:", result.value, "done:", result.done);
let iterator = collection[Symbol.iterator]();
let result = iterator.next();
console.log("First result:", result.value, "done:", result.done);
result = iterator.next();
console.log("Second result:", result.value, "done:", result.done);
result = iterator.next();
console.log("Third result:", result.value, "done:", result.done);
Here’s how it works:
- collection[Symbol.iterator](): This creates the iterator for the given collection (like an array, set, or string).
- iterator.next(): This method is called to get the next item in the collection. It returns an object with two properties: value (the current item) and done (a boolean indicating if we’ve reached the end of the collection).
- console.log("First result:", result.value, "done:", result.done): This logs the first value and its corresponding done status (true or false).
- console.log("Second result:", result.value, "done:", result.done): This logs the second value and done status after calling next() again.
- console.log("Third result:", result.value, "done:", result.done): This logs the third value and the done status after calling next() once more.
These console.log statements will help you see how the iterator moves through the collection step by step. After each call to next(), you'll get the current item and whether you're done iterating through the collection.
Creating a Custom Iterator
You can create your own iterator by defining an object that returns a next() method. This method should return an object with the properties value (the current value) and done (a boolean indicating whether the iteration is complete).
function createIterator() {
let count = 1;
return {
next() {
if (count <= 3) { // let collection length is 3
return { value: count++, done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
const iterator = createIterator();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
function createIterator() {
let count = 1;
return {
next() {
if (count <= 3) { // let collection length is 3
return { value: count++, done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
const iterator = createIterator();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
How It Works:
- let count = 1: The iterator starts with the value 1.
- next(): This method is responsible for returning the current value and incrementing count each time it's called.
- If count <= 3, the iterator returns the current value and sets done to false.
- When count exceeds 3, it returns done: true to indicate the iteration is finished.
Example 1: Using a Built-in Iterator to Loop Through an Array
In this example, we’ll use the built-in iterator to loop through an array of numbers. This will allow us to access each number one at a time without directly using a loop like for or forEach.
let numbers = [10, 20, 30, 40, 50];
// Get the iterator for the array
let iterator = numbers[Symbol.iterator]();
let result = iterator.next();
// Iterate through the array
while (!result.done) {
console.log("value:", result.value, "done:", result.done);
result = iterator.next();
}
let numbers = [10, 20, 30, 40, 50];
// Get the iterator for the array
let iterator = numbers[Symbol.iterator]();
let result = iterator.next();
// Iterate through the array
while (!result.done) {
console.log("value:", result.value, "done:", result.done);
result = iterator.next();
}
How It Works:
- let numbers = [10, 20, 30, 40, 50]: We create an array of numbers.
- let iterator = numbers[Symbol.iterator]();: We get the iterator for the array using Symbol.iterator. This iterator will let us loop through each element of the array.
- let result = iterator.next();: We call next() to get the first element in the array.
- while (!result.done): This loop keeps running as long as done is false. It ensures we keep iterating through the array until we’ve reached the end.
- console.log("value:", result.value, "done:", result.done);: We log the current value and the done status to the console. The value is the element in the array, and done tells us if we’re at the end of the array.
- result = iterator.next();: After logging the current item, we call next() again to move to the next element in the array.
Output
value: 10 done: false
value: 20 done: false
value: 30 done: false
value: 40 done: false
value: 50 done: false
value: 10 done: false
value: 20 done: false
value: 30 done: false
value: 40 done: false
value: 50 done: false
Once the iterator reaches the last element, the done property will be true, and the loop will stop.
Example 2: Iterating Over an Array with a Custom Iterator
In this example, we’ll create a custom iterator that loops through an array of names. The iterator will return each name one by one, and will indicate when the iteration is complete.
function createArrayIterator(array) {
let index = 0;
return {
next() {
if (index < array.length) {
return { value: array[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
const names = ['Tom', 'Jack', 'Charlie'];
const iterator = createArrayIterator(names);
console.log(iterator.next()); // { value: 'Tom', done: false }
console.log(iterator.next()); // { value: 'Jack', done: false }
console.log(iterator.next()); // { value: 'Charlie', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
function createArrayIterator(array) {
let index = 0;
return {
next() {
if (index < array.length) {
return { value: array[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
const names = ['Tom', 'Jack', 'Charlie'];
const iterator = createArrayIterator(names);
console.log(iterator.next()); // { value: 'Tom', done: false }
console.log(iterator.next()); // { value: 'Jack', done: false }
console.log(iterator.next()); // { value: 'Charlie', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
How It Works:
- createArrayIterator(array): This function creates a custom iterator for the passed array.
- index = 0: The iterator starts at the first index of the array.
- next(): This method returns the current name in the array and increments the index.
- When the iterator reaches the end of the array, it returns done: true, signaling the end of the iteration.
Output
{ value: 'Tom', done: false }
{ value: 'Jack', done: false }
{ value: 'Charlie', done: false }
{ value: undefined, done: true }
{ value: 'Tom', done: false }
{ value: 'Jack', done: false }
{ value: 'Charlie', done: false }
{ value: undefined, done: true }
Frequently Asked Questions
What is an iterator in JavaScript?
What is an iterator in JavaScript?
An iterator is an object with a next() method that returns the next value in a sequence and a done status indicating completion. It helps traverse collections one item at a time.
What is the difference between iterable and iterator?
What is the difference between iterable and iterator?
An iterable is any object that has a [Symbol.iterator]() method (like arrays or strings). An iterator is the object returned by that method and includes a next() function to access items.
How do you create a custom iterator in JavaScript?
How do you create a custom iterator in JavaScript?
You can define a custom iterator by creating an object with a next() method that returns an object with value and done properties. For iterability, add a [Symbol.iterator] method.
Can you loop over iterators using for...of?
Can you loop over iterators using for...of?
Yes, if the iterator is also an iterable (i.e., it has a [Symbol.iterator]() method), it can be used with for...of. Most built-in iterators like those from arrays or sets support this.
What are some built-in JavaScript iterables?
What are some built-in JavaScript iterables?
Arrays, Strings, Maps, Sets, and TypedArrays are all built-in JavaScript iterables. They implement the [Symbol.iterator]() method and return iterators for traversing their elements.
What's Next?
In the next section, you will explore JavaScript generators, which provide a simpler and more memory-efficient way of working with iterators. You’ll also see how to use the yield keyword for creating custom generators.