JavaScript Iteration Complete Tutorial

In this section, we will learn what the Iteration is and how to use it in JavaScript.

Iteration Meaning

The word `iteration` inherited from a Latin word which is `itero`, meaning “repeat” or “do again”.

What is JavaScript Iteration?

In the context of programming, the term `iteration` means executing a procedure for multiple times and usually with an expectation of a termination.

The `for` loop is a simple example of iteration:

for (let i = 0 ; i<5; i++){
        console.log(i);
}

The loops are fundamental iterative tool because they allow us to specify how many iterations should occur and what should happen during each iteration.

For example, we can use the `for` loop and iterate through the elements of an array:

const arr = ["Red","Green","Blue"];
      for (let i = 0 ; i<arr.length; i++){
        console.log(arr[i]);
      }

Output:

Red

Green

Blue

Here, because we can get the size of an array via the `length` property and also use the index number to traverse through all the items, we could invoke the `for` loop to iterate through the elements of an array.

But we can’t use the `for` loop for all other data sources (like a database or a typical object-literal) for the reason that:

  • Incrementing an integer to access sequential indices is specific to an array type and does not generalize to other data structures that have an implicit ordering.

If we can’t use loops to iterate through other types of data source, the question is: what should we do for other types of data source if we want to get its content one by one like the way we do for arrays?

The solution to this problem is the `Iterator Pattern`:

The iterator pattern is a solution in which something can be described as `iterable` and so implement a protocol known as the `Iterable` interface.

When a data source becomes iterable, there are a couple of native language constructs that can accept such a data source and return all its elements.

Example of these constructs:

So if we can turn a data source (like an object) into an iterable object, then all the constructs mentioned above can use that object to return its elements.

How to Implement Iteration Pattern in JavaScript?

In short, there are two protocols that need to be implemented on a non-iterable object to turn it into an iterable object:

  • Iterable Protocol
  • Iterator Protocol

JavaScript Iterable Protocol

This protocol applies to any non-iterable object that wants to be an iterable. The object needs to have a property with the key `[Symbol.iterator]` and a method as its value. This method returns an object that we call it `Iterator object`.

The body of the iterator-object complies with the `Iterator` protocol that we’ll explain in just a second.

Example: implementing iterable protocol in JavaScript

For now, let’s see an object that has applied the first protocol, which is `Iterable`:

const obj = {
  [Symbol.iterator]: function(){
  return {/*body...*/}
  }
}

As you can see, this `obj` object has the `[Symbol.iterator]` property and a method as its value that returns an object.

Alright now let’s see the structure of this returned object that is known as the `Iterator` object.

JavaScript Iterator Protocol

Each iterable object has an iterator object that can be used to iterate through the elements of that iterable object.

The iterator object has a `next()` method to advance through its associated iterable object. Each time we call the `next()` method, it should return an object that we call the `IteratorResult` and it contains the next element of the iterable object.

The `IteratorResult` object has two properties:

  • `done`: The value of this property can be either `ture` or `false`. If the value is `true` it means there’s at least another element in the iterable object and we can call the `next()` method once again to get that element. But, if the value of this property is `false` it means there’s no other element in the target iterable-object to return.
  • `value`: This property contains the next value (element) of the iterable or the value `undefined` if the property `done` is set to `true` (Meaning there’s no element in the target iterable-object to be returned).

Example: implementing iterator protocol in JavaScript

const obj = {
  [Symbol.iterator]: function(){
    let counter = 0;
    return {
      next(){
        counter ++;
        if (counter == 1){
          return {value:"One",done: false};
        }
        if (counter ==2){
          return {value:"Two",done:false};
        }
        if (counter ==3){
          return {value:"Three",done:false}
        }
        return {value: undefined, done: true}
      }
    }
  }
}
const iterator = obj[Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

Output:

{value: "One", done: false}

{value: "Two", done: false}

{value: "Three", done: false}

{value: undefined, done: true}

{value: undefined, done: true}

In this program, after implementing both Iterable and Iterator protocols on the `obj` object, the object is now iterable and its elements (values) which are “One”, “Two”, and “Three”, can be accessed using the iterator object.

In the statement:

const iterator = obj[Symbol.iterator]();

We called the `[Symbol.iterator]` method to get the `Iterator` object of the `obj` so that we can use it to get the elements of the `obj`.

After that, any time we called the `next()` method of the `iterator`, we got the next element of the `obj` in the form of an object. Obviously, we could call the returned object’s `value` property to specifically get the value and not the entire object.

For example:

console.log(iterator.next().value);

This would get the `value` property of the returned object.

Note: the `obj` object had only 3 elements, but we invoked the `iterator.next()` statement 5 times. Well, for the first 3 calls, we got all three elements, but the next two calls returned us the value `undefined` and the `done: true`. This means calling the `next()` method of the iterator object beyond the number of elements in that object has the idempotent effect. Which basically means has no effect other than returning the object `{value: undefined, done: true}`.

JavaScript for of loop and iterable objects

Alright, in the last example we called the `iterator` object of the `obj` manually. But in JavaScript as mentioned before, there are constructs like `for of` loop that can be used on an iterable object and they will automatically traverse and return all the elements of an iterable object.

Example: using for of loop on an iterable objects

const obj = {
  [Symbol.iterator]: function(){
    let counter = 0;
    return {
      next(){
        counter ++;
        if (counter == 1){
          return {value:"One",done: false};
        }
        if (counter ==2){
          return {value:"Two",done:false};
        }
        if (counter ==3){
          return {value:"Three",done:false}
        }
        return {value: undefined, done: true}
      }
    }
  }
}
for (const value of obj){
  console.log(value);
}

Output:

One

Two

Three

As you can see, we just passed the iterable object `obj` to the `for of` loop and it returned all the elements (values) of this iterable object.

JavaScript Built-in Types That Implemented Iterable and Iterator Protocols

Other than developers defined iterable object, there are many built-in types that implement both `Iterable` and `Iterator` protocols.

For example:

  • Strings
  • Arrays
  • Maps
  • Sets
  • Some DOM collection types, like NodeList,

This means an object of types mentioned above, already has the [Symbol.iterator] method-property and the iterator object.

Example: String value and for of loop

for (const value of "Symbol"){
  console.log(value);
}

Output:

S

y

m

b

o

l

In this program, by invoking the `for of` loop on the string value “Symbol”, the execution engine invoked the `iterator object` of the string object “Symbol” and returned all the characters of this string which are considered as the elements of this string.

JavaScript Arrays and Iterable Object

Because arrays are also iterable, we can invoke the `for of` loop on an array as well. In situations like this, the execution engine will invoke the `Symbol.iterator` method-property of the target array to get its iterator. And then via that iterator, it will return all the elements of that array.

Example: JavaScript Arrays and for of

for (const value of ["One","Two","Three"]){
  console.log(value);
}

Output:

One

Two

Three

Leave a Reply