Iterators in JavaScript ES6
ES6 has come up with a very cool and much needy concept of Iterators. All C++ or Java coders are completely familiar with what are iterators.
But, Iterators in JavaScript is something new and needs a little bit of understanding.
What are Iterators ? (Definition from Cplusplus.com)
An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators.
In JavaScript we do not need operators, since everything in JS is a variable, so all we need is a variable defined as an iterator that shall move.
Lets look into the basic for each loop available in JS
var a = [1,2,3,4,5]; for(var i in a) { console.log("The Position of "+a[i]+" is " + i ); } //// Result //// "The Position of 1 is 0" "The Position of 2 is 1" "The Position of 3 is 2" "The Position of 4 is 3" "The Position of 5 is 4"
This loop is fairly simple and iterates over each element one by one and returns the index. Let us understand a new concept of For Of loop with the same example.
var a = [1,2,3,4,5]; for(var i of a) { console.log("The value is " + i ); } //// Result //// "The value is 1" "The value is 2" "The value is 3" "The value is 4" "The value is 5"
This loop simply gets you the value. Before, I move on, let me clear the difference in these loops. For In loop does not necessarily force the order of the array where as for of loop can be defined to either follow the order or not. All you need to do is define the iterator.
Lets understand the above statements with following example -
var a = {'a':1,'c':2,'b':3} for(let x in a) { console.log(a[x] + " " + x); } //// Prints //// "1 a" "2 c" "3 b" //// See the order of the keys. //// Same with For of loop - for(let x of a) { console.log(x); } // Returns the following error - TypeError: a[Symbol.iterator] is not a function
By applying the same concept, we received an error saying Symbol.Iterator is not defined. Now this Symbol.Iterator is nothing but a way to define the call of Next function to let the browser know what to do after moving to next element and also, moving to next element is required or not.
The Prototype of Symbol.Iterator is as following -
a[Symbol.Iterator] = function() { return { next : function() {} } }
So now lets write a function to determine the behavior of our iterator to iterate in ordered manner -
a[Symbol.iterator] = function () { var _this = this; var keys = null; var index = 0; return { next: function () { if (keys === null) { keys = Object.keys(_this).sort(); } return { value: keys[index], done: index++ >= keys.length }; } } }
If you are familiar with the Closures in Javascript, this function shouldn't be difficult to understand. Anyways, at first we define some variables to be used. Then we create an index variable initialized with 0 to start the access of 1st element. Then we return the next function which checks if actually the next function was called or not. If yes, sort the keys and then simply return the value and a boolean done with true or false. When done returns true, the iterator knows to stop.
lets see the result now -
for (var x of a) { console.log(x + " " + a[x]); } /// Result - "a 1" "b 3" "c 2"
There you go. we get the loop in the order we defined. That is the power of this new Iterator.
Moving on, You can define an infinite iterator, without worrying about the break condition. All you need to do is make the done part of next function always return False. Of course, you need to define some logic in your for loop to break out.