ECMAScript 6 - for of loops
In a previous article we talked about generators and I mentioned that it’s important and interesting to make use of for of loops with generators. So what are for of loops? Let’s start first by talking about loops in general. The most popular loop, that we all know and love, is of course the for loop. It’s pretty tried and tested at this point. He’s a little reminder for you:
var arr = [ 'a', 'b', 'c' ];
for (var i=0; i<arr .length; i++){
console.log(i+' : '+arr[i]); //"0 : a", "1 : b" , "2 : c"
}
But there are a few issues here. First, it sets an array numbered from 1 to n. But if we don’t have one like that (for example an array with 5 members but 2 and 3 are completely missing while 6 and 7 are populated) then the entire array will have no value at all.
It’s just for scenarios like this that we have the for in loop that works great with arrays and objects.
var person = {fname:'John', lname:'Doe', age:25};
for (var prop in person){
if (Object.prototype.hasOwnProperty.call(person, prop)){
console.log(prop+' : '+person[prop]); //"fname : John", "lname : Doe", "age : 25"
}
}
So what’s the problem with it? There are actually a few problems with it. The first is that it doesn’t pass through the array members or through object properties in the order you would expect it to. Also, it will also skip empty members. It will also pass through all of the shared members in the prototype chain, and there’s also a problem with its implementation which is not recommended in general. I’ll give you the simplest example:
let iterable = [3, 5, 7];
iterable.foo = "hello";
for (let i in iterable) {
console.log(i); // logs 0, 1, 2, "foo"
}
What I did here is I ran it on the array, but look what happens. It’s possible in principle to make it work like we want with the array and with the object, but this requires a lot of code.
There is also the forEach that you can run solely on values. The problem here is that you can’t stop it while it’s running and it works only on arrays.
Because of all of this most people use lodash or underscore or even jQuery in order to use forEach properly on an array or object. For of solves this problem in arrays and the like, in that it provides an easy and comfortable way to get things done, and the loops can be stopped without issue.
How does it work? It’s easy as pie:
var arr = ['hello', 'world', 'I', 'am', 'Ran'];
for ( var arrValue of arr ) {
console.log(arrValue); // 'hello', 'world', 'I', 'am', 'Ran'
}
If I add all kinds of weird things to the array (with or without a prototype chain) the for of will elegantly ignore them. Have a look:
var arr = ['hello', 'world', 'I', 'am', 'Ran'];
arr.moshe = 'Levi';
for ( var arrValue of arr ) {
console.log(arrValue); // 'hello', 'world', 'I', 'am', 'Ran'
}
You can also pass through a text sting:
var string = 'hello';
for ( var value of string ) {
console.log(value); // 'h', 'e', 'l', 'l', 'o'
}
Also when it comes to objects there’s a nice bypass we can use:
var obj = { foo : 'hello', bar : 'world' };
for ( var key of Object.keys(obj) ) {
console.log(key + "->" + obj[key]); // 'foo->hello', 'bar->world'
}
As I promised at the beginning, one of the best things about for of is that you can break it while it’s running. This is great when it comes to generators. Want an little example? Check it:
function* myGenerator() { // a generator function
var curr = 0;
while (true) {
curr++;
yield curr;
}
}
for (var n of myGenerator()) {
console.log(n);
// truncate the sequence at 100
if (n >= 100) {
break;
}
}
What’s going on here? We have a very simple generator that iterates from 0 to infinity. At each iteration it gets to yield. Since I have no criteria for stopping, I’ll receive 1,2,3,4 until the for of decides to break the generator, in our case when the number will be equal or greater than 100.
Note that I didn’t use next—the iterator of the for of does it for me.
Complicate you say? I give you another example:
function* myGenerator() { // a generator function
yield 'a';
yield 'b';
yield 'c';
yield 44;
}
for (var n of myGenerator()) {
console.log(n); //'a', 'b', 'c', 44
}
Maybe this is easier to understand, instead of using an ugly foreach and using a next to manually bring the next yield. I’m running the generator via for of. In each iteration I get the result of yield without the need of next. I can stop the for of at any time using break.
This is of course a theoretical example. In reality the generator will have heavier tasks to carry out and the break will have more importance in regard to performance. What’s important is that with other methods you have to use next each time and weigh its impact, but with the for of loop it’s done for you and have only to specify the stopping criteria. And if you don’t specify, the generator will continue until it causes the loop to yield. This is what makes for of so useful when it comes to generators, maybe more than anything.
About the author: Ran Bar-Zik is an experienced web developer whose personal blog, Internet Israel, features articles and guides on Node.js, MongoDB, Git, SASS, jQuery, HTML 5, MySQL, and more. Translation of the original article by Aaron Raizen.
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment