465

Do you think there is a big difference in for...in and for loops? What kind of "for" do you prefer to use and why?

Let's say we have an array of associative arrays:

var myArray = [{'key': 'value'}, {'key': 'value1'}];

So we can iterate:

for (var i = 0; i < myArray.length; i++)

And:

for (var i in myArray)

I don't see a big difference. Are there any performance issues?

mikemaccana
  • 81,787
  • 73
  • 317
  • 396
andrii
  • 9,079
  • 9
  • 33
  • 42
  • 13
    Note that we also, [as of JS 1.6](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach), have: `myArray.forEach(callback[, thisarg])`. – Benji XVI Jan 06 '12 at 10:32
  • 14
    @Benji array.forEach is actually in ES5. – mikemaccana Jan 11 '12 at 20:59
  • 2
    in a for-in loop you need a conditional that looks like this: `if(myArray.hasOwnProperty(i)){true}` – Eric Hodonsky Mar 27 '12 at 22:18
  • 6
    `['foo', 'bar', 'baz'].forEach(function(element, index, array){ console.log(element, index, array); });` is OK to use pretty much everywhere except in IE8- and it's by far the most elegant syntax – Jon z Sep 26 '12 at 17:51
  • 5
    There is also `for...of` statement in [ECMAScript 6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of), for example: `for (let i of myArray) console.log(i);` – Vitalii Fedorenko May 05 '15 at 23:01

22 Answers22

549

The choice should be based on the which idiom is best understood.

An array is iterated using:

for (var i = 0; i < a.length; i++)
   //do stuff with a[i]

An object being used as an associative array is iterated using:

for (var key in o)
  //do stuff with o[key]

Unless you have earth shattering reasons, stick to the established pattern of usage.

Community
  • 1
  • 1
AnthonyWJones
  • 178,910
  • 32
  • 227
  • 302
  • 39
    It should be mentioned that it is a nice practice to use for...in with filtering if statement. There is a handy method of Object "obj.hasOwnProperty(member)" which checks if a member returned by iterator is actually member of the object. See: http://javascript.crockford.com/code.html – Damir Zekić Oct 29 '08 at 23:09
  • 58
    As commented at another answer(s), the "for...in" does not work correctly for Arrays, as it will iterate over all Array properties and methods. Thus, you should use "for...in" only for iterating over object properties. Otherwise, stick to "for(i=0; i – Denilson Sá Maia Apr 10 '10 at 18:03
  • For performance reasons, IMO it's better to evaluate the length of the array before the `for`, not evaluate a.length each time in the loop. – UpTheCreek Mar 22 '12 at 13:46
  • 9
    @UpTheCreek: That is definitely true when the array is in fact something returned by the HTMLDOM, however, I wonder how big a standard javascript array would need to be before you could see an appreciable difference? Personally I would keep the code as simple as possible until its proven necessary to do something different. – AnthonyWJones Mar 22 '12 at 18:14
  • At some point I began to use `for (var i = 0, l = a.length; i < a; i++) {}` and stuck with it. It's a little more complex than just `i < a.length` and its effect on performance in most cases is not worth mentioning, but it gets easier to type each time and at least I regard it as a "cleaner" method because a.length doesn't have to be evaluated each time. I can say I'm happy with my switch from MooTools a.each(...). – jpeltoniemi Dec 19 '12 at 02:55
  • 2
    @Pichan I think you mean `i < l`, not `i < a`, in your for-loop condition. – Max Nanasy Jan 08 '13 at 03:28
  • @MaxNanasy Yeah, so much for "easier to type each time" :D – jpeltoniemi Jan 12 '13 at 14:44
  • for (var i = 0; i < a.length; i++) method can't be used for a sparse array like when you do; myArray[110]="foo"; myArray[180]="fie"; – jedi Dec 30 '14 at 14:58
  • You should get the length of the array before the `for` loop because otherwise the `.length` will get evaluated each iteration of the loop. – Ron Mar 27 '15 at 17:24
  • Just found an interesting bug. `for ... in statement` will cast integer into a string when iterating an array of integers. – Raynal Gobel Sep 03 '17 at 15:25
  • you learn something new everyday... – elad silver Feb 04 '21 at 19:27
162

Douglas Crockford recommends in JavaScript: The Good Parts (page 24) to avoid using the for in statement.

If you use for in to loop over property names in an object, the results are not ordered. Worse: You might get unexpected results; it includes members inherited from the prototype chain and the name of methods.

Everything but the properties can be filtered out with .hasOwnProperty. This code sample does what you probably wanted originally:

for (var name in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, name)) {
        // DO STUFF
    }
}
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
Benno Richters
  • 14,488
  • 14
  • 38
  • 41
  • Second that - foreach... isn't doing what you might expect (esp if coming from .net) and it's probably not what you're trying to do. – marcus.greasly Oct 28 '08 at 16:20
  • 70
    for...in is perfectly appropriate for looping over object properties. It is not appropriate for looping over array elements. If you can't understand the difference between these scenarios, then yes, you should avoid for...in; otherwise, go nuts. – Shog9 Oct 28 '08 at 18:40
  • 8
    Want to emphasize the fact that it is NOT ORDERED! This could be a big problem, and would be difficult bug to catch. – Jason Aug 04 '09 at 17:39
  • 1
    In theory it's not ordered, but in all modern browsers, it is (except in some weird cases in Chrome, apparently). I believe future JavaScripts will have guaranteed ordering. – Nosredna Aug 04 '09 at 18:02
  • 4
    +1 for "it includes members inherited from the prototype chain and the name of methods." You'll have fun if someone happens to use your code with Prototype loaded (even if your code doesn't actually use it), for instance. – ijw Aug 05 '09 at 12:11
  • 13
    Please don't forget to **declare** the `name` variable: `for(var name in object)...`, otherwise, if that code is inside a function for example, the `name` variable end up being a property of the global object (an assignment to an *undeclared identifier* does that), also in the new ECMAScript 5 Strict Mode, that code will throw a `ReferenceError`. – Christian C. Salvadó Oct 23 '10 at 21:08
  • Also beware that if you iterate over a Class you will get it's children including all its user defined prototypes etc. This isn't very efficient even if you use hasOwnProperty() and another scenario to stick with a simple for statement. As mentioned only go near for in statements when you have Associative Arrays – Denis Hoctor Dec 21 '10 at 00:19
  • 6
    @Nosredna: There's an issue about order of iteration for Chrome, filed by none other than John Resig, that is marked as WontFix. http://code.google.com/p/chromium/issues/detail?id=883 . Even before chrome, the order of iteration was not the same across browsers if you remove and then add a property again. Also IE 9 behaves a lot like chrome (supposedly for speed improvements). So... Please stop spreading inaccurate information, you'd be very naïve to keep depending on it. – Juan Mendes Sep 01 '11 at 21:54
  • @Nosredna: See the "Remarks" section under http://msdn.microsoft.com/en-us/library/55wb2d34(v=vs.94).aspx. – Juan Mendes Sep 01 '11 at 22:00
62

FYI - jQuery Users


jQuery's each(callback) method uses for( ; ; ) loop by default, and will use for( in ) only if the length is undefined.

Therefore, I would say it is safe to assume the correct order when using this function.

Example:

$(['a','b','c']).each(function() {
    alert(this);
});
//Outputs "a" then "b" then "c"

The downside of using this is that if you're doing some non UI logic, your functions will be less portable to other frameworks. The each() function is probably best reserved for use with jQuery selectors and for( ; ; ) might be advisable otherwise.


Jason
  • 2,521
  • 25
  • 28
  • 4
    There's always http://documentcloud.github.com/underscore/ which has _.each and a whole lot of other useful functions – w00t Nov 29 '11 at 11:01
  • 1
    does it also mean if I have length property in my object $.each will fail? e.g. x= { a:"1", b:"2", length:3 }. – Onur Topal Jun 13 '13 at 12:17
29

there are performance differences depending on what kind of loop you use and on what browser.

For instance:

for (var i = myArray.length-1; i >= 0; i--)

is almost twice as fast on some browsers than:

for (var i = 0; i < myArray.length; i++)

However unless your arrays are HUGE or you loop them constantly all are fast enough. I seriously doubt that array looping is a bottleneck in your project (or for any other project for that matter)

Gene
  • 1,487
  • 1
  • 14
  • 15
  • 5
    Would storing "myArray.length" into a variable before looping make the performance difference go away? My guess is "yes". – Tomalak Oct 28 '08 at 11:10
  • It would make at least most of it go away. However if I remember correctly i-- is marginally faster than i++. In any case the differences are very small. – Gene Oct 28 '08 at 11:14
  • But we are still talking JavaScript here, not assembler, aren't we? :-) – Tomalak Oct 28 '08 at 12:19
  • I'm not sure anymore :D I know I was but don't know about you – Gene Oct 28 '08 at 14:49
  • '.' is quite appallingly poor performance in JS (or, at least, IE7 JS), in my experience; it's worth strength-reducing for it, as here. – ijw Aug 05 '09 at 12:10
  • 3
    No. 'myArray.length' is a property, not a method on an object--no calculation is done to determine its value. Storing its value in a variable will do nothing at all. – jason Nov 01 '09 at 07:34
  • 3
    Yes there is. Properties are not variables; they do have get/set code. – ste May 25 '10 at 13:11
  • 12
    I tend to use `for(var i = myArray.length; i--;)` – Kevin Sep 15 '10 at 10:48
  • 1
    The fastest way is to use a while loop: `var l = myArray.length; while (i--) { }` – Renaat De Muynck Jan 20 '12 at 13:05
  • 1
    @RenaatDeMuynck, good call, but you assign length to `l` and decrement `i` - need to pick one. This is also equivalent to `for(var i = myArray.length - 1; i--; ) { }`. – Patrick M Jul 13 '12 at 05:40
  • 1
    I tested that for(var i=0,n=myArray.length;i – Yeti Sep 22 '13 at 12:33
  • Historically, reverse while was king: `var L=arr.length; while(L--){}`. Then (around FF 3.5 era) `for` was better optimized (probably because it was used the most, especially by 'script-kiddy' code). In that era, reverse `for` was king: `for(var L=arr.length; L--;){}`. Then recently optimizations became much more intelligent and we could finally start noticing CPU Cache-misses. Chunking in parts of (for example) int-arrays is required for every smaller/reverse index, whilst going forwards uses cache as intended. Because `for` is still faster, now the regular forwards-loop is often king. – GitaarLAB Dec 18 '14 at 04:11
  • 2
    Code for clarity and readability. Not for what happens to run marginally faster in some browsers when using absurdly massive arrays at the current moment in time. Optimizations may change, but your code's readability (or lack thereof) will not. Write code that others can easily follow, and let the optimizers catch up in their own due time. – aroth Apr 27 '15 at 04:47
26

Note that the native Array.forEach method is now widely supported.

Sam Dutton
  • 13,238
  • 6
  • 50
  • 61
  • 2
    What does it do? Does it have the problems mentioned in other posts (looping over properties instead of elements of array)? Also, as IE8 does not support it, it is bit of a stretch to say it is widely supported. – Rauni Lillemets Aug 16 '11 at 08:13
  • 2
    as much as *nix users despise it, IE8 is most of all sub-windows7 users. thats a massive portion of the browser market. – sbartell Sep 12 '11 at 18:30
  • 2
    @Rauni -- I take your point, but for desktop devices IE browser share is less than 40%, according to http://en.wikipedia.org/wiki/Usage_share_of_web_browsers#Summary_table, and according to http://marketshare.hitslink.com/browser-market-share.aspx?qprid=2&qpcustomd=0 and other sites, at least 8% of browsers are IE 9. In other words, Array.forEach is supported by around 70% of desktop browsers, so I don't think 'widely supported' is unreasonable. I haven't checked, but mobile support (on WebKit and Opera browsers) may be even higher. Obviously, there are considerable variations geographically. – Sam Dutton Sep 13 '11 at 11:44
  • 1
    Thanks for the update. I agree that it could be said that it is "widely supported". Only problem is that if user uses this JS method, He/She still has to write a back-up method for the case if it is not supported.. – Rauni Lillemets Sep 27 '11 at 12:17
  • 1
    @Rauni -- you can use es5-shim and es6-shim to automatically provide backup methods. https://github.com/es-shims/es5-shim – Michiel van der Blonk May 09 '15 at 11:46
  • @MichielvanderBlonk - The most generous estimate for people still using IE 7 or older that I can find in 2015 is 15%, from NetApplications. Most other sources list it as 3% or less - trivial enough that I think you can ignore them. – ArtOfWarfare Jul 30 '15 at 01:27
24

Updated answer for 2012 current version of all major browsers - Chrome, Firefox, IE9, Safari and Opera support ES5's native array.forEach.

Unless you have some reason to support IE8 natively (keeping in mind ES5-shim or Chrome frame can be provided to these users, which will provide a proper JS environment), it's cleaner to simply use the language's proper syntax:

myArray.forEach(function(item, index) {
    console.log(item, index);
});

Full documentation for array.forEach() is at MDN.

mikemaccana
  • 81,787
  • 73
  • 317
  • 396
  • 1
    You should really document the callback's parameters: 1st the element value, 2nd the element index, 3rd the array being traversed – drewish Jan 26 '12 at 04:02
  • I hear what you're saying, but in this case oversimplifying it obscures the full range of possibility. Having both the index and value means it can serve as a replacement for both for...in and for each...in—with the bonus that you don't have to remember which iterates over keys or values. – drewish Jan 29 '12 at 01:30
  • There are a ton of people in corporate environments who are still stuck on IE 6, 7, and 8. I would definitely make sure that your choice of implementation is appropriate for your audience. – Cᴏʀʏ Jul 13 '12 at 20:25
  • 1
    @Cory: ES5 forEach can be added to legacy ES3 browsers fairly easily. Less code is better code. – mikemaccana Jul 27 '12 at 11:02
  • 2
    @nailer Can this be used on arrays and objects interchangeably? – hitautodestruct Jan 16 '13 at 09:51
  • 1
    @hitautodestruct It's part of Array's prototype, not Object's. Generally in the community right now non-Array objects are still iterated with 'for ( var key in object ) {}'. – mikemaccana Mar 08 '13 at 15:21
14

I second opinions that you should choose the iteration method according to your need. I would suggest you actually not to ever loop through native Array with for in structure. It is way slower and, as Chase Seibert pointed at the moment ago, not compatible with Prototype framework.

There is an excellent benchmark on different looping styles that you absolutely should take a look at if you work with JavaScript. Do not do early optimizations, but you should keep that stuff somewhere in the back of your head.

I would use for in to get all properties of an object, which is especially useful when debugging your scripts. For example, I like to have this line handy when I explore unfamiliar object:

l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);

It dumps content of the whole object (together with method bodies) to my Firebug log. Very handy.

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
Damir Zekić
  • 14,512
  • 2
  • 27
  • 34
  • Link is now broken. Sure would like to see the benchmark, if someone has another link. – Billbad Mar 28 '12 at 17:42
  • Foreach loops break in prototype? As it is now commonly supported, that is something prototype should be solving. – mvrak Oct 25 '13 at 21:49
  • Link in answer is outdated - *"404 | Not Found | The content that you're looking is no longer on this page"*. – Pang Oct 22 '20 at 01:05
14

The two are not the same when the array is sparse.

var array = [0, 1, 2, , , 5];

for (var k in array) {
  // Not guaranteed by the language spec to iterate in order.
  alert(k);  // Outputs 0, 1, 2, 5.
  // Behavior when loop body adds to the array is unclear.
}

for (var i = 0; i < array.length; ++i) {
  // Iterates in order.
  // i is a number, not a string.
  alert(i);  // Outputs 0, 1, 2, 3, 4, 5
  // Behavior when loop body modifies array is clearer.
}
Mike Samuel
  • 109,453
  • 27
  • 204
  • 234
14

Using forEach to skip the prototype chain

Just a quick addendum to @nailer's answer above, using forEach with Object.keys means you can avoid iterating over the prototype chain without having to use hasOwnProperty.

var Base = function () {
    this.coming = "hey";
};

var Sub = function () {
    this.leaving = "bye";
};

Sub.prototype = new Base();
var tst = new Sub();

for (var i in tst) {
    console.log(tst.hasOwnProperty(i) + i + tst[i]);
}

Object.keys(tst).forEach(function (val) {
    console.log(val + tst[val]);
});
Community
  • 1
  • 1
meloncholy
  • 1,962
  • 16
  • 15
  • 2
    damn, that's sneaky. It was worth reading 50 other post to get to this. obj={"pink":"ducks", red: "geese"}; Object.keys(obj) === ["pink", "red"] – Orwellophile Jul 10 '12 at 08:32
7

here is something i did.

function foreach(o, f) {
 for(var i = 0; i < o.length; i++) { // simple for loop
  f(o[i], i); // execute a function and make the obj, objIndex available
 }
}

this is how you would use it
this will work on arrays and objects( such as a list of HTML elements )

foreach(o, function(obj, i) { // for each obj in o
  alert(obj); // obj
  alert(i); // obj index
  /*
    say if you were dealing with an html element may be you have a collection of divs
  */
  if(typeof obj == 'object') { 
   obj.style.marginLeft = '20px';
  }
});

I just made this so I'm open to suggestions :)

6

I'd use the different methods based on how I wanted to reference the items.

Use foreach if you just want the current item.

Use for if you need an indexer to do relative comparisons. (I.e. how does this compare to the previous/next item?)

I have never noticed a performance difference. I'd wait until having a performance issue before worrying about it.

Matt Lacey
  • 64,328
  • 10
  • 87
  • 143
  • See Bnos answer below - for...in isn't doing what you expect here and if you use it you may well have all kinds of fun. For the record, Prototype does things the *right* way. – marcus.greasly Oct 28 '08 at 16:22
4

Watch out!

If you have several script tags and your're searching an information in tag attributes for example, you have to use .length property with a for loop because it isn't a simple array but an HTMLCollection object.

https://developer.mozilla.org/en/DOM/HTMLCollection

If you use the foreach statement for(var i in yourList) it will return proterties and methods of the HTMLCollection in most browsers!

var scriptTags = document.getElementsByTagName("script");

for(var i = 0; i < scriptTags.length; i++)
alert(i); // Will print all your elements index (you can get src attribute value using scriptTags[i].attributes[0].value)

for(var i in scriptTags)
alert(i); // Will print "length", "item" and "namedItem" in addition to your elements!

Even if getElementsByTagName should return a NodeList, most browser are returning an HTMLCollection: https://developer.mozilla.org/en/DOM/document.getElementsByTagName

baptx
  • 2,297
  • 2
  • 25
  • 38
4

With for (var i in myArray) you can loop over objects too, i will contain the key name and you can access the property via myArray[i]. Additionaly, any methods you will have added to the object will be included in the loop, too, i.e., if you use any external framework like jQuery or prototype, or if you add methods to object prototypes directly, at one point i will point to those methods.

pilsetnieks
  • 10,005
  • 12
  • 45
  • 60
3

For in loops on Arrays is not compatible with Prototype. If you think you might need to use that library in the future, it would make sense to stick to for loops.

http://www.prototypejs.org/api/array

Chase Seibert
  • 15,061
  • 5
  • 48
  • 58
  • Forget "you might need to use that library". Think instead "your JS might be included with *anything else* that uses that library", because the problems still come. – ijw Aug 05 '09 at 12:14
3

I have seen problems with the "for each" using objects and prototype and arrays

my understanding is that the for each is for properties of objects and NOT arrays

Benjamin Lee
  • 1,140
  • 3
  • 13
  • 18
3

A shorter and best code according to jsperf is

keys  = Object.keys(obj);
for (var i = keys.length; i--;){
   value = obj[keys[i]];// or other action
}
bormat
  • 1,100
  • 10
  • 16
3

If you really want to speed up your code, what about that?

for( var i=0,j=null; j=array[i++]; foo(j) );

it's kinda of having the while logic within the for statement and it's less redundant. Also firefox has Array.forEach and Array.filter

fabjoa
  • 1,415
  • 2
  • 14
  • 15
  • 2
    Why would this speed up your code? I can't see why reording statements like this would speed it up. – Rup Dec 05 '11 at 11:04
2

for(;;) is for Arrays : [20,55,33]

for..in is for Objects : {x:20,y:55:z:33}

angelito
  • 360
  • 3
  • 8
1

Use the Array().forEach loop to take advantage of parallelism

PazoozaTest Pazman
  • 731
  • 10
  • 33
  • 4
    JavaScript in the browser is event loop concurrent so `Array.prototype.forEach` will not execute multiple calls to the callback in parallel. – Mike Samuel Jun 28 '12 at 18:12
0

Be careful!!! I am using Chrome 22.0 in Mac OS and I am having problem with the for each syntax.

I do not know if this is a browser issue, javascript issue or some error in the code, but it is VERY strange. Outside of the object it works perfectly.

var MyTest = {
    a:string = "a",
    b:string = "b"
};

myfunction = function(dicts) {
    for (var dict in dicts) {
        alert(dict);
        alert(typeof dict); // print 'string' (incorrect)
    }

    for (var i = 0; i < dicts.length; i++) {
        alert(dicts[i]);
        alert(typeof dicts[i]); // print 'object' (correct, it must be {abc: "xyz"})
    }
};

MyObj = function() {
    this.aaa = function() {
        myfunction([MyTest]);
    };
};
new MyObj().aaa(); // This does not work

myfunction([MyTest]); // This works
Paulo Cheque
  • 2,497
  • 19
  • 20
0

There is an important difference between both. The for-in iterates over the properties of an object, so when the case is an array it will not only iterate over its elements but also over the "remove" function it has.

for (var i = 0; i < myArray.length; i++) { 
    console.log(i) 
}

//Output
0
1

for (var i in myArray) { 
    console.log(i) 
} 

// Output
0 
1 
remove

You could use the for-in with an if(myArray.hasOwnProperty(i)). Still, when iterating over arrays I always prefer to avoid this and just use the for(;;) statement.

achecopar
  • 315
  • 9
  • 16
0

Although they both are very much alike there is a minor difference :

var array = ["a", "b", "c"];
array["abc"] = 123;
console.log("Standard for loop:");
for (var index = 0; index < array.length; index++)
{
  console.log(" array[" + index + "] = " + array[index]); //Standard for loop
}

in this case the output is :

STANDARD FOR LOOP:

ARRAY[0] = A

ARRAY[1] = B

ARRAY[2] = C

console.log("For-in loop:");
for (var key in array)
{
  console.log(" array[" + key + "] = " + array[key]); //For-in loop output
}

while in this case the output is:

FOR-IN LOOP:

ARRAY[1] = B

ARRAY[2] = C

ARRAY[10] = D

ARRAY[ABC] = 123

Yash Srivastava
  • 642
  • 2
  • 7
  • 13