Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between for(i in array) and for(var i=0;i<array.length;i++) [duplicate]

This would be a very easy question for all you javascript/jquery guys.

I've been programming javascript from past 2 years and today I faced a strange problem.

I am fetching a JSONarray from my C# Webmethod and calling it by jQuery.ajax()

When I do

for (i in JSONRaw) {
    Index = Index + 1;
    $('#bottomGridDashboard').append('<tr> <td>' + Index + '</td> <td>' + JSONRaw[i].DisplayName + '</td> <td>' + JSONRaw[i].SpeedInKPH + '</td> <td><img src="' + JSONRaw[i].ImageURL + '" height="20px" alt="" /></td> <td>' + JSONRaw[i].DepotID + '</td> <td>' + JSONRaw[i].RouteID + '/' + JSONRaw[i].ScheduleID + '/' + JSONRaw[i].TripID + '</td> <td>' + JSONRaw[i].Direction + '</td> <td>' + JSONRaw[i].LastStop + '</td> <td> ' + JSONRaw[i].ETAMinutes + ' </td> </tr>');
}

the appended table adds two extra rows putting every field as 'undefined'. See this Image

However if i replace the loop with

for (var i = 0; i < JSONRaw.length;i++ ) {
    Index = Index + 1;
    $('#bottomGridDashboard').append('<tr> <td>' + Index + '</td> <td>' + JSONRaw[i].DisplayName + '</td> <td>' + JSONRaw[i].SpeedInKPH + '</td> <td><img src="' + JSONRaw[i].ImageURL + '" height="20px" alt="" /></td> <td>' + JSONRaw[i].DepotID + '</td> <td>' + JSONRaw[i].RouteID + '/' + JSONRaw[i].ScheduleID + '/' + JSONRaw[i].TripID + '</td> <td>' + JSONRaw[i].Direction + '</td> <td>' + JSONRaw[i].LastStop + '</td> <td> ' + JSONRaw[i].ETAMinutes + ' </td> </tr>');
}

the undefined rows disappear.. See the image

I apologize for my stupidity but I have never faced any such problem before. What could be the reason??

EDIT:

The array is perfectly fine. And there are no holes in it. Another observation is that the undefined properties appear only at the bottom of my grid. I think it is processing two extra indexes more than the array length.

EDIT-2

My console.log showed me the following elements in my array.

http://i.imgur.com/rI5TjdK.jpg

I've declared the prototypes in my Master page.

Array.prototype.inArray = function (comparer) {
    for (var i = 0; i < this.length; i++) {
        if (comparer(this[i])) return true;
    }
    return false;
};


Array.prototype.pushIfNotExist = function (element, comparer) {
    if (!this.inArray(comparer)) {
        this.unshift(element);
    }
};

Is it increasing the array length. ? ?

like image 969
writeToBhuwan Avatar asked Nov 23 '13 09:11

writeToBhuwan


People also ask

Can we use for in for array?

Using for (var property in array) will cause array to be iterated over as an object, traversing the object prototype chain and ultimately performing slower than an index-based for loop. for (... in ...) is not guaranteed to return the object properties in sequential order, as one might expect.

What is length of an array?

Basically, the length of an array is the total number of the elements which is contained by all the dimensions of that array. Syntax: public int Length { get; } Property Value: This property returns the total number of elements in all the dimensions of the Array.

How do you find the length of an array in JavaScript?

The JavaScript array length property states the number of items in an array. To find the length of an array, reference the object array_name. length. The length property returns an integer.


2 Answers

JavaScript's for-in and C#'s foreach are quite different things. Don't use for-in to loop through arrays unless you use the appropriate safeguards, that's not what it's for. It loops through enumerable properties of objects, not array indexes or entries.

Either use the necessary safeguards, or use a generic for like your second example, or (if you can rely on having it) use Array#forEach.

More in this SO answer and on my blog.


Separately: Be sure you're declaring i somewhere (you don't seem to be in your first example). If you don't, you fall prey to The Horror of Implicit Globals.


I've declared the prototypes in my Master page.

Array.prototype.inArray = function ...

This is why you don't use for-in for looping through arrays without safeguards. Again, see the links above. Your for-in loop will loop through the array index properties ("0", "1", and so on -- yes, they're really strings) and also the names of the functions you've added to the Array.prototype (inArray and such).

like image 157
T.J. Crowder Avatar answered Sep 30 '22 17:09

T.J. Crowder


There are a few ways those two loops are different.

(1) The first should be for (var i in JSONRaw). Setting the property i on window may have non-obvious consequences.

(2) JSONRaw is not an array, but an object which happens to have a ill-defined length property.

(3) There have been other properties set on JSONRaw that appear in the the first loop.

(4) The array could have "holes". For example, the array below has a hole at index 1.

var a = [];
a[0] = 0;
a[2] = 2;

The first way would omit the 1. The second way would include the index 1 (with a[1] being undefined).

A similar situation can happen as follows:

var a = [0, 1];
a.length = 3;

Personally, I suspect (3).

Doing a console.log in the first loop may reveal the problem.

EDIT: From your debugging output, it seems (3) was the culprit. inArray and pushIfNotExist are keys on all arrays, so the first for loop iterated over them.

If you are going to to use the first loop, you have three options:

(1) Don't add those functions on Array.prototype. Adding to built-in prototypes is generally discouraged.

(2) Use Object.defineProperty (won't work in IE8):

Object.defineProperty(Array.prototype, 'inArray', {
    enumerable: false,   //this makes it not show up in the for loop
    value: function (comparer) {
        for (var i = 0; i < this.length; i++) {
            if (comparer(this[i])) return true;
        }
        return false;
    }
});

(3) Check to see if the key was defined on the prototype.

for(var i in JSONRaw) {
    if(JSONRaw.hasOwnProperty(i)) {
        //do something
    }
}

Though most people just use the second loop because of the potential pitfalls (and faster performance).

like image 35
Paul Draper Avatar answered Sep 30 '22 15:09

Paul Draper