65.9K
CodeProject is changing. Read more.
Home

JavaScript For Loops 101

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4 votes)

May 21, 2014

CPOL

9 min read

viewsIcon

18950

All you ever wanted to know about the for loop in JavaScript and all its variants

What?! JavaScript doesn't have a for-each loop? You gotta be kidding me!

That was my reaction to my co-worker whose code I was peer-reviewing.

Background

By their very nature, JavaScript's arrays are sparse. See this and this. My colleague had some extensive operations on a sparse array and I thought the performance can be improved by using a for-each loop instead of a for loop to iterate over the array. But surely, he hasn't seen client side JavaScript code in the web world that uses a for-each loop.

So we sat down and did some research. And we came across this exhaustive discussion on StackOverflow. We realized that JavaScript has many variants of the for loop. We had to refer to various other articles on the web to fully understand the concept and syntax. IMO they are not really advertised well enough for beginners. Which means a beginner would always try to mold his program to a vanilla for implementation instead of using a variant that is more suitable to the situation. Also, what makes matters more complex is not all the variants are available in all environments (e.g., browsers, servers).

Seemed like some documentation was needed.

Introduction

This article intends to be an all-you-ever-wanted-to-know tutorial about the for loop in JavaScript and all its variants.

A Word about ECMAScript, JavaScript and Feature Mismatch

JavaScript is an implementation of ECMAScript which is a set of specifications laid out in ECMA-262 and ISO/IEC 16262. So if you see this, you will notice that different browsers and different versions of these browsers support different versions of ECMAScript implementation. In other words, they support different versions of JavaScript. Which in turn means not all features of ECMAScript are available in all versions of JavaScript and not all features of JavaScript are available in all browsers. So one has to be careful writing code that works across environments and provide alternatives for environments that do not support certain features. We will discuss this aspect while talking about different flavors of the for loop.

For a quick reference to which browser version supports which version of JavaScript and ECMAScript, see this.

So, tell me about all types of for loops!

Plain Old Vanilla for loop

Syntax

for (statement 1; statement 2; statement 3) {
    //code block to be executed
}

Statement 1 is executed before the code block starts. Normally, you will use statement 1 to initiate the variable used in the loop (var index = 0).

Statement 2 defines the condition for running the code block. Often, statement 2 is used to evaluate the condition of the initial variable.

Statement 3 is executed each time after the code block has been executed. Often, statement 3 increments or decrements the initial variable.

All the 3 statements are optional.

Example

var index;
var myArray = ["a", "b", "c"];
for (index = 0; index < myArray.length; ++index) {
    console.log(myArray[index]);
} 

Simple enough!

forEach

So they DO have a forEach loop after all!

But it is only supported by environments that are compliant to ECMAScript edition 5. That means IE 9 or later and Firefox 4 or later. See this.

Okay! Let's get the basics first.

Syntax

array.forEach(callback [, contextObject]){
    //code block to be executed
}

Parameters

callback: The callback function to execute for each element (required)

contextObject: Object to be used as a context for the callback function (optional)

Example

var index;
var myArray = ["a", "b", "c"];
myArray.forEach(function(entry) {
    console.log(entry);
});

For more examples, see this.

Why This is Better

The callback function is automatically invoked with three arguments: the value of the element, the index of the element and the Array object being traversed. Which means you don't have to declare indexing and entry variables in the current scope, as they're supplied as arguments to the iteration function. So their scope is limited to just that iteration. We will use an example to understand this.

In a classic for loop:

var myArray = ["a", "b", "c"];
for (var i = 0; i < myArray.length; i++) {
  setTimeout(function() {
     console.log(myArray[i]);
  }, 500);
}

But it doesn't work. Why?!

Because, the variable scoping rules are different in JavaScript from languages like C#.

  1. There is no concept of block-scope in JavaScript. A "var" variable is accessible from everywhere inside the function where it was defined. This is function scope. If it is created outside of a function, it’ll become a global variable. In our case, when the i < myArray.length condition stops the loop, the value of i is actually 3.
  2. JavaScript passes the arguments of a function as references. When the console.log(myArray[i]) is called, it uses the referenced value of i, which still exists within the scope, because a function created in a function can access the references of the parent function.
  3. setTimeout() is an async method and it waits the specified number of milliseconds, and then executes the specified function. By this time, the for loop has finished and the value of i is 3 at that time, so when console.log() is finally executed, it prints the value of elements[3] - undefined - three times.

Now, there is a workaround to this:

for (var i = 0; i < myArray.length; i++) {
  (function(index) {
    setTimeout(function() {
       console.log(myArray[index]);
    }, 500)})(i);
}

This works as expected. But is it really easy to understand? Compare this with the forEach version below.

myArray.forEach(function(myArray) {
  setTimeout(function() {
    console.log(myArray);
  }, 500);
});

Much better and readable code. You can focus more on your logic than bothering about the mechanics of the iteration, i.e., how to iterate through an array, how to handle scopes.

You may be concerned about the impact on performance in making a function call for each array entry. This article shows why you shouldn't be. In fact, some of it may be more than made up for by the fact that the forEach() version uses less memory, because the very same function is used in each iteration. Whereas in the for loop, we create a new function every time, and these stay alive until their scope ends.

Warning

As mentioned earlier, this may not work in older browsers such as Internet Explorer 8. But no fret. There is an easy workaround.

Insert the following code at the beginning of your scripts. This algorithm is exactly the one specified in ECMA-262, 5th edition, assuming Object and TypeError have their original values and that callback.call evaluates to the original value of Function.prototype.call.

if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisArg */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        fun.call(thisArg, t[i], i, t);
    }
  };
}

for...in

Now this one is a bit tricky. You have to handle it carefully!

T. J. Crowder has written the most comprehensive guide to for...in.

A for...in loop only iterates over enumerable properties. It DOES NOT loop through the indexes of an array. Try to print it in your mind as best as you can. Before I elaborate further, let's get the basics right.

Syntax

for (variable in object) {
    //code block to be executed
}

Parameters

  • variable: A different property name is assigned to variable on each iteration
  • object: Object whose enumerable properties are iterated

Example

var myObject = {prop1:1, prop2:2, prop3:3};
function show_props(obj, objName) {
  var result = "";    
  for (var prop in obj) {
    result += objName + "." + prop + " = " + obj[prop] + "\n";
  }    
  return result;
}
console.log(show_props(myObject, "myObject"));

Output:
myObject.prop1 = 1
myObject.prop2 = 2
myObject.prop3 = 3

Okay!

Now back to the caveat that we were discussing. for..in loops through the enumerable property names of an object, not the indexes of an array. For example, this is WRONG!

var myArray, index;
myArray = ['a', 'b', 'c'];
for (index in myArray) { 
    console.log("myArray[" + index + "] = " + myArray[index]);
}

Output
myArray[0] = a 
myArray[1] = b 
myArray[2] = c 

The output is all right. But this won't be the same in all environments and hosts. So, this is not the right usage. You ask why? Well, that is not what for...in is designed for.

In the example (right after syntax) above which shows the loop that went through each of the properties of the object myObject - there is no guarantee whatsoever in which order these properties will be read. Arrays are nothing but objects in JavaScript and array indexes are nothing but property names. Any other property added to the prototype of the object or prototype of the object's prototype all the way up to the top of the chain of inheritance will all be listed using for...in.

In other words, you cannot add anything to myArray or myArray's prototype or its prototype's prototype, etc. if you want the 2nd example of this section to work in a predictable manner. If you are a pro JavaScript programmer, you would know that in the real world, you will not be able to live with this restriction for too long.

Fair enough! I get it! I will not use for...in to loop through index of an Array; instead I will use it loop through all the enumerable properties of an object. But you just said any other property added to the prototype of the object or prototype of the object's prototype all the way up to the top of the chain of inheritance will all be looped through? I don't want that!

Correct. There is a way to stop this. And that is the key to the correct usage of for...in.

var myArray = {a:1, b:2, c:3};
function ParentArray() {
  this.color = "red";
}
ParentArray.prototype = myArray;
function show_own_properties(obj, objName) {
  var result = "";    
  for (var prop in obj) {
    if( obj.hasOwnProperty( prop ) ) { 
      result += objName + "." + prop + " = " + obj[prop] + "\n";
    } 
  }    
  return result;
}
p = new ParentArray();
console.log(show_own_properties(p, "p")); /* alerts: o.color = red */ 
console.log(show_own_properties(myArray, "myArray")); 
/* alerts: myArray.a = 1
myArray.b = 2
myArray.c = 3 */ 

hasOwnProperty function is built into all objects. It tells us whether the property is on the object itself (returns true), rather than being inherited from the object's prototype (returns false). This deals with any enumerable properties that might have been added to Array.prototype.

Also, notice this code will always access only the properties that are present. For an Array such as this:

var a = [];
a[0] = "item1";
a[100] = "item2";
a[500] = "item3";

It will only access 3 elements and loop 3 times; not loop through 501 times. That is why it is more suitable than a vanilla for loop in cases of sparse Arrays. And as we know from the beginning that JavaScript Arrays are sparse by their nature.

for...of

This is part of the Harmony (ECMAScript edition 6) proposal. So if you decide to use it, first check the browser compatibility here.

This variant of for loop is essentially an implicit usage of iterators (see Further Reading section). While for...in iterates over property names, for...of iterates over property values:

Syntax

for (variable of object) {
  //code block to be executed
}

Parameters

  • variable: On each iteration, a value of a different property is assigned to variable
  • object: Object whose enumerable properties are iterated

Example

The following example shows the difference between a for...of loop and a for...in loop.

let arr = [ 3, 5, 7 ];
arr.foo = "hello";

for (let i in arr) {
   console.log(i); // logs "0", "1", "2", "foo"
}

for (let i of arr) {
   console.log(i); // logs "3", "5", "7"
}

Under the covers, that gets an iterator from the array and loops through it. It uses an iterator defined by the object (the array), and arrays define that their iterators iterate through their entries (not their properties).

Reverse for Loop

This is not really a new feature or construct, but just looping backwards in a vanilla for loop.

Example

for (var i=array.length; i--; ) {
     //code block to be executed
}
OR
for (var i=array.length; i-->0 ;) {
    //code block to be executed
}

See this nice post on it. It takes a bit of getting used to but is quite handy in certain situations. You don't need to declare a temporary length variable here or compare against Array.length on each iteration, both of which might be minute optimizations though. There is another discussion on it which debates at length about the performance benefits of it.

Further Reading

  1. Explicit iterator (part of ES6+)
  2. If you are not familiar with the prototype property in JavaScript, then read this.

History

  • 21st May 2014: v1