Categories
arrays for-loop iteration javascript loops

Why is using “for…in” for array iteration a bad idea?

2006

I’ve been told not to use for...in with arrays in JavaScript. Why not?

7

  • 48

    I saw the recent question where someone said that to you, but they only meant for Arrays. It is considered bad practice for iterating through arrays but not necessarily for iterating through members of an object.

    – mmurch

    Nov 23, 2010 at 21:21

  • 21

    Lots of answers with “for” loops such as ‘for (var i=0; i<hColl.length; i++) {}’ compare to ‘var i=hColl.length; while (i–) {}’ which, when it is possible to use the latter form it is substantially faster. I know this is tangential but thought I would add this bit.

    Jun 22, 2011 at 15:06

  • 3

    @MarkSchultheiss but that’s reverse iteration. Is there another version of forward iteration that’s faster?

    – ma11hew28

    Oct 10, 2012 at 11:28

  • 5

    @Wynand use var i = hCol1.length; for (i;i;i--;) {} cache the i as it will make a difference, and simplify the test. – the older the browser, the more difference between for and while ALWAYS cache the “i” counter – and of course negative does not always fit the situation, and the negative while obfuscate the code a bit for some people. and note var i = 1000; for (i; i; i--) {} and var b =1000 for (b; b--;) {} where i goes 1000 to 1 and b goes 999 to 0. – the older the browser, the more the while tends to favor for performance.

    Mar 14, 2013 at 13:07


  • 10

    You can also be clever. for(var i = 0, l = myArray.length; i < l; ++i) ... is the fastest and best you can get with forward iteration.

    Jul 17, 2013 at 17:02


1682

The reason is that one construct:

var a = []; // Create a new empty array.
a[5] = 5;   // Perfectly legal JavaScript that resizes the array.

for (var i = 0; i < a.length; i++) {
    // Iterate over numeric indexes from 0 to 5, as everyone expects.
    console.log(a[i]);
}

/* Will display:
   undefined
   undefined
   undefined
   undefined
   undefined
   5
*/

can sometimes be totally different from the other:

var a = [];
a[5] = 5;
for (var x in a) {
    // Shows only the explicitly set index of "5", and ignores 0-4
    console.log(x);
}

/* Will display:
   5
*/

Also consider that JavaScript libraries might do things like this, which will affect any array you create:

// Somewhere deep in your JavaScript library...
Array.prototype.foo = 1;

// Now you have no idea what the below code will do.
var a = [1, 2, 3, 4, 5];
for (var x in a){
    // Now foo is a part of EVERY array and 
    // will show up here as a value of 'x'.
    console.log(x);
}

/* Will display:
   0
   1
   2
   3
   4
   foo
*/

21

  • 419

    Remember to use (var x in a) rather than (x in a) – don’t want to create a global.

    Nov 25, 2010 at 2:24


  • 90

    First issue isn’t a reason it’s bad, only a difference in semantics. Second issue seems to me a reason (on top of clashes between libraries doing the same) that altering the prototype of a built-in datatype is bad, rather than that for..in is bad.

    – Stewart

    Mar 1, 2011 at 0:52


  • 91

    @Stewart: All objects in JS are associative. A JS Array is an object, so yes, it’s associative too, but that’s not what it’s for. If you want to iterate over an object’s keys, use for (var key in object). If you want to iterate over an array’s elements, however, use for(var i = 0; i < array.length; i += 1).

    – Martijn

    Mar 1, 2011 at 15:15

  • 48

    You said for the first example, that it Iterates over numeric indexes from 0 to 4, as everyone expects, I expect it to iterate from 0 to 5! Since if you add an element in position 5, the array will have 6 elements (5 of them undefined).

    – stivlo

    Oct 22, 2011 at 10:53


  • 29

    I think the examples would be even clearer if you set a[5] to something other than 5, say, a[5]=42. The fact that the second example (“for (x in a)” only enumerates one value is not surprising to me; the fact that the value it enumerates is 5 instead of 42 is surprising to me (coming from other languages with a similar construct that enumerates list contents instead of array indices).

    – metamatt

    Dec 3, 2012 at 23:56


416

The for-in statement by itself is not a “bad practice”, however it can be mis-used, for example, to iterate over arrays or array-like objects.

The purpose of the for-in statement is to enumerate over object properties. This statement will go up in the prototype chain, also enumerating over inherited properties, a thing that sometimes is not desired.

Also, the order of iteration is not guaranteed by the spec., meaning that if you want to “iterate” an array object, with this statement you cannot be sure that the properties (array indexes) will be visited in the numeric order.

For example, in JScript (IE <= 8), the order of enumeration even on Array objects is defined as the properties were created:

var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';

for (var p in array) {
  //... p will be "2", "1" and "0" on IE
}

Also, speaking about inherited properties, if you, for example, extend the Array.prototype object (like some libraries as MooTools do), that properties will be also enumerated:

Array.prototype.last = function () { return this[this.length-1]; };

for (var p in []) { // an empty array
  // last will be enumerated
}

As I said before to iterate over arrays or array-like objects, the best thing is to use a sequential loop, such as a plain-old for/while loop.

When you want to enumerate only the own properties of an object (the ones that aren’t inherited), you can use the hasOwnProperty method:

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    // prop is not inherited
  }
}

And some people even recommend calling the method directly from Object.prototype to avoid having problems if somebody adds a property named hasOwnProperty to our object:

for (var prop in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, prop)) {
    // prop is not inherited
  }
}

6

  • 10

    See also David Humphrey’s post Iterating over Objects in JavaScript Quickly – for array’s for..in is much slower than “normal” loops.

    Nov 25, 2010 at 2:25

  • 18

    Question about the last point about “hasOwnProperty”: If someone overrides “hasOwnProperty” on an object, you’ll have problems. But won’t you have the same problems if someone overrides “Object.prototype.hasOwnProperty”? Either way they’re screwing you up and it’s not your responsibility right?

    Jan 14, 2011 at 0:08

  • You say for..in is not bad practice, but it can be misused. Have you got a real world example of good practice, where you really did want to go through all of an objects properties including inherited properties?

    – rjmunro

    Jul 3, 2013 at 12:05

  • 4

    @ScottRippey: If you want to take it there: youtube.com/watch?v=FrFUI591WhI

    May 29, 2014 at 15:24

  • 1

    with this answer I found that can access the value with for (var p in array) { array[p]; }

    – equiman

    Apr 20, 2017 at 13:08


126

There are three reasons why you shouldn’t use for..in to iterate over array elements:

  • for..in will loop over all own and inherited properties of the array object which aren’t DontEnum; that means if someone adds properties to the specific array object (there are valid reasons for this – I’ve done so myself) or changed Array.prototype (which is considered bad practice in code which is supposed to work well with other scripts), these properties will be iterated over as well; inherited properties can be excluded by checking hasOwnProperty(), but that won’t help you with properties set in the array object itself

  • for..in isn’t guaranteed to preserve element ordering

  • it’s slow because you have to walk all properties of the array object and its whole prototype chain and will still only get the property’s name, ie to get the value, an additional lookup will be required

0