DEV Community

Ayako yk
Ayako yk

Posted on

Understanding Iterables, Iterators, and Their Role in JavaScript

Iterables and iterators are fundamental concepts in JavaScript. However, they are not discussed or directly used in code as often as other features like functions, so I initially struggled to understand why tutorials emphasize this concept. After gaining more experience, I realized how crucial it is to understand iterables and iterators in order to write clean and efficient code.

Iterables
Iterables are objects that can be iterated over, or looped through, such as Array, String, Map, Set, etc.
(Note: string (lowercase) is a primitive type, but String with a capital "S" refers to a wrapper object that allows access to string-related methods and properties.)

Most tutorials only discuss iterables in the context of the for..of loop, which confused me at first. While the for..of loop is a common way to work with iterables, they are also used in many other contexts.

So, first, let's learn about iterables using a for..loop.

Syntax of a for..of loop

for (variable of iterable) {
  // code block to be executed
}
Enter fullscreen mode Exit fullscreen mode

W3Schools

Examples
With a string:

const str = "hello";
for ( let char of str ) {
    console.log(char); // h, e, l, l, o
Enter fullscreen mode Exit fullscreen mode

With an array:

const numbers = [1, 2, 3, 4];
for (let num of numbers) {
    console.log(num); // 1, 2, 3, 4
}
Enter fullscreen mode Exit fullscreen mode

Iterators

An Iterator object is an object that conforms to the iterator protocol by providing a next() method that returns an iterator result object. All built-in iterators inherit from the Iterator class. The Iterator class provides a Symbol.iterator method that returns the iterator object itself, making the iterator also iterable. It also provides some helper methods for working with iterators.

The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite), and potentially a return value when all values have been generated.

MDN

Let me simplify that:
An iterator is an object that contains a next() method. This method returns an object with two properties: done and value.
{ done: Boolean, value: any }

value: The current value in the sequence of values from the iterable.
done: A boolean that indicates whether the iterator has completed iterating. If done is true, there are no more values to process, and iteration can stop.

When a for..of loop starts, it calls a method that returns an iterator. The for..of loop then works with the returned object to iterate over the iterable.

What is that method?

It's Symbol.iterator.
e.g. obj[Symbol.iterator]()

Symbol.iterator is a static data property. "Symbol.iterator" is a key, which is why square brackets are used, and the Symbol ensures the value is unique.

Prototype objects of Arrays, Strings, Maps, and similar structures have Symbol.iterator methods. This is what makes them iterable.

// Create an Object
myNumbers = {};

// Make it Iterable
myNumbers[Symbol.iterator] = function() {
    let n = 0;
    done = false;
    return {
        next() {
            n += 10;
            if (n == 100) {done = true}
            return {value:n, done:done};
        }
    };
}

Now you can use for..of
for (const num of myNumbers) {
  // Any Code Here
}
Enter fullscreen mode Exit fullscreen mode
let iterator = myNumbers[Symbol.iterator]();

while (true) {
  const result = iterator.next();
  if (result.done) break;
  // Any Code Here
}
Enter fullscreen mode Exit fullscreen mode

W3Schools

We don't need to explicitly call [Symbol.iterator]() because built-in iterables already have this method. When we use a for..of loop or other iterable-handling methods, it is called automatically.

You might encounter it written as @@iterator(), where @@<symbol-name> is used to represent well-known Symbols. However, according to MDN, this notation is no longer used.
MDN

As mentioned above, iterables are not limited to use with a for..of loop. Another example is the spread operator.

var arr = [3, 4, 5];
var arr2 = [1, 2, ...arr, 6];

console.log(arr2); // [1, 2, 3, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

codeguage

This works similarly to the other examples discussed.
The arr is an iterable object that internally calls [Symbol.iterator](). This method enables the spread operator to iterate over the array's elements using the next() method and the {done: Boolean} properly to determine when to stop iterating.

It was challenging for me to grasp the idea, and it took me some time. There's probably more to explore on this topic, including Generator. But for now, this serves as a good starting point to understand the core concept of JavaScript.

Top comments (0)