In almost every single JavaScript application we write there is always some form of looping through collections. Looping collections becomes necessary when we receive data through an HTTP request for example.
Since data can take on many forms, not every algorithm looping over them is able to get the job done more quickly and/or efficiently than other looping methods.
In this case, there's an obvious problem: We need to be able to switch between different algorithms for iterating through collections whenever we need to. A design pattern that solves this specific problem is called the Iterator Design Pattern.
With that said, in this post, we will be going over the Iterator Design Pattern in JavaScript and implementing one hands-on. We will learn why a different algorithm becomes necessary when developing.
How the Iterator Pattern Visually Looks Like
This is what the pattern looks like from a visual perspective:
![client user interface, collection [item 1, item 2, etc.] goes to iterator, then goes to iterator algorithm, then loops to collection, then goes back to iterator.](https://miro.medium.com/v2/resize:fit:700/0*-kylKy8iPahVc5k6.png)
Implementation
Let's pretend we have an array arr which is a collection of numbers:
If we're developing a program and we have a commonly used function that takes in a list of values and a callback which returns a value that we're looking for using the callback as the source of truth, one of the most obvious readily available strategies we can use is the for loop:
Or we can use the Iterator Pattern and instead work with different variations of iterations treating them as injectable algorithms. Here's the code:
The reason why it is better to abstract out the implementation details is that collections can come in various data structures. Some data structures can be traversed more efficiently with alternate algorithms. We can allow our objects to be able to switch from one iterator to another in the runtime whenever there are more sufficient algorithms to finish the task.
Let's continue on with our example and create a simple iterator:
We're able to loop through the collection and see the results:

What if we had a nested collection of items? Our current iteration method is no longer efficient because it doesn't account for key values that are deeper, as shown below:

Collections of data can become very complex and they're not always just plain JSON objects. Programs in JavaScript often fetch data structures, transform them and only make them publicly available to the outside with functions to work with to do common tasks like generating a final collection of data.
This is why the Iterator pattern is important as it promotes extensibility, scalability, and composition.
With that said, we can use a different algorithm to get all descendants of our elems collection, which you can see below:

I'm sure you have noticed the syntax Symbol.iterator. JavaScript uses this to place the default iterator for any object we attach this to. Don't be confused and assume that this is part of the pattern. It's just syntax sugar. We are simply taking advantage of this syntax to enable the for of to operate which is something entirely related to JavaScript.
Let's hop straight back into the Iterator Pattern. There's not really much of a useful use case shown in these examples yet to see how powerful it can become but we did go through an issue it solved in a practical use case.
So, let's extend our examples even further to add more control to how we want to work with collections because understanding the next parts is crucial to understanding how this pattern really helps us.
What we have so far is a nested collection of representational DOM objects. We exposed one issue we had when using a regular for loop where it wasn't enough to cover deep collections so we implemented a variation of the Iterator Pattern to satisfy our needs.
However, it would be very helpful to have the ability in each iteration to be able to see where we currently are in complex data structures.
Let's pretend we want access to the current item (which we currently do), the current depth we are in (each access to an element's children increases depth), the current index of the collection, the previous as well as the next item in the collection, the previous, current, and next element in the iteration (this is not the same as the current collection), and what the items in the iteration currently look like.
With all of this information, we're able to do pretty much anything we want to with our collection of elements.
This is how we can implement that:
All we need to do now is to invoke it and provide a callback. Our callback will be provided all of this information on each iteration:
Here's the results:
Conclusion
I hope you have found valuable information here. Look out for more in the future!