Monday, January 14, 2019

Iterators in Javascript

Javascript is becoming mature day by day, and in order to make it much interactive and better in the ways of coding, ECMAScript keeps on adding different features to it.

One of the new features (not so new, 😜), is the Iterators & Iterables.

So in a layman language, Iterators & Iterables go hand in hand.

Iterables are those objects(Classes in the real sense) those have implemented the Iterator function.

Now comes the question what is iterable, so, anything that can be iterated is termed as Iterable and the property that makes it iterable is the Iterator.

1. Explanation

So, here is the quick info regarding the things we read till now:
  1. Iterable: is basically a property that needs to be implemented to make a class/object iterable. This is done by implementing a method whose key is Symbol.iterator. Symbol.iterator is a factory of iterators.
  2. Iterator: is a function that returns a function named next() which again returns an object with 2 keys namely: done & value, so a basic iterator() looks like this:

    1
    2
    3
    4
    5
    6
    7
    8
    return{
        next(){
            return({
                done: true/false, //boolean
                value: item, //item to be read
            })
        }
    }
    
2. Questions

2.1 Q:
Now the question arises, where are these iterators useful, so let's take a look at the traversing an array in a normal fashion.

1
2
3
let a = [1, 2, 3, 4];
for(let i=0; i < a.length; i++)
   console.log(a[i]);

A: Same functionality with for..of loop, that internally uses the iterators, to traverse the array or any iterable.

1
2
for(let v of a)
	console.log(v)

As you can see how clean and compact it is, to traverse an iterable if the iterators are implemented in a proper manner.

2.2 Q: Now how do you tell whether a class implemented the iterator or not?

A: If console.log(typeof array[Symbol.iterator]) returns a function that means the Iterator is implemented and the object of that class can be browsed or traversed using the special for loops.

Now let us take a basic example, where I created the Class with 2 variables and then I implemented the iterator in order to traverse all the variables of the object of the same class.

For the reference here is the code.

Let us try to see the code in detail. So basically code has 2 files, User.js (the class) and index.js (file that created the object of User class and tries to utilize iterator.)

User.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class User {
    constructor({name, age}){
        this.name = name;
        this.age = age;
    }

    getAge(){ return this.age; }
    getName(){ return this.name; }

    setName(name){ this.name = name; }
    setAge(age){ this.age = age; } 

    //this is the property that needs to be implemented for iterators
    [Symbol.iterator]() {
        let self = this;
        let data = Object.keys(this);
        return{
            next(){
                return({
                    done: data.length === 0,
                    value: self[data.pop()]                
                })
            }
        }
    }
}

module.exports = User;

index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let User = require("./User");

let user1 = new User({name: 'AV', age: 31});
let user2 = new User({name: 'AV', age: 32});

console.log('\nIterating USER1')
for(const a of user1) {
    console.log(a)
}
console.log('\nIterating USER2')
for(const a of user2) {
    console.log(a)
}

The code of User.js is pretty simple, we have created a class that takes 2 parameters namely, name & age, but the catch is at line no 14, User.js.

At line 14, User.js, we have implemented the iterator for the class User, and in order to do that we have called a function named [Symbol.iterator] & have provided the functionality of the iterator. In that iterator, we have returned a function at line 17, with the structure we discussed at point 1.2 (under Explanation section)

The iterator is a function that returns a function named next() & it internally returns an object with 2 keys, namely done (line no 20, User.js) & value (line no 21, User.js).

In the iterator, we are taking the value from the self-object (line no 15, User.js) and the done value is the boolean that checks whether all values of the object are traversed or not.

The code of index.js is pretty straight forward, as we are just traversing the object (keys) using for..of loop at line 7 & 11, index.js.

Note: The example I took is a basic example of showing the functionality of Iterators, although implementing the iterator in this fashion is not a good practice.

Hope you enjoyed and understood the Iterators.


Happy coding.
:)

No comments:

Post a Comment