$.each() vs for() loop - and performance

Solution 1:

One thing that .each() allows you to do that can't be done with a for loop is chaining.

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

I played around with your JSFiddle to see how chaining would influence performance in cases where you have to loop through subsets of the original set of matched elements.

The result wasn't all that unexpected, although I think the overhead of end() was exaggerated here because of the combination of few elements and many loops. Other than that: plain JS loops are still slightly faster, but whether that weighs up to the added readability of .each() (and chaining) is debatable.

Solution 2:

One thing you do get with .each() is automatic local scoping (because you are invoking an anonymous function for every object), which in turn means if you are creating even more anonymous functions/closures/event handlers/whatever on every iteration, you never have to worry about your handlers sharing a variable. That is, JavaScript doesn't act like other languages when it comes to local scopes, but because you can declare a variable anywhere, it can fool you sometimes.

In other words, this is wrong:

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

Whenever any of those objects invoke their "someEvent" after this loop (please note that this is made up), the alert is always going to say whatever was last assigned to idx, which should be (as of the time invoked) someObjectArray.length;

To make sure you save the proper index, you have to declare a local scope, create a variable and assign to that variable for use.

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

As you can see, that's as ugly as hell, but it should work. Each event handler gets its own copy of localidx

Now compare that to .each()

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

A lot simpler, isn't it?

Solution 3:

jQuery.each vs for-loop

Advantages jQuery.each:

  • Fits well in jQuery code (chaining and style).
  • No worries about scope (references to the iterator and object will be persistent).
  • Can be used universally (for all kinds of objects and iterating over object keys).

Advantages for-loop:

  • High performance (for games/animations/large datasets).
  • Full control over iterator (skip items, splice items from list, etc).
  • The for-loop will always work, for there is no dependency on jQuery.
  • Same familiar syntax as most other similar languages.

Example code

This is example code of how I prefer to iterate over a list.

var list = ['a', 'b', 'c', 'd', 'e', 'f'];

jQuery.each:

$.each(list, function(i, v)
{
    // code...
});

For-loop without closure:

for(var i=0,v,n=list.length;i<n;i+=1)
{
    v = list[i];
    // code...
}

For-loop with closure:

for(var i=0,n=list.length;i<n;i+=1)
{
    (function(i, v)
    {
        // code...
    })(i, list[i]);
}

Note: I suggest you just use the standard for-loop, and only use a closure when necessary. However, when your code looks more like jQuery than Javascript anyway, it could be easier to just use $.each. In case of performance issues, you could always look into it afterwards.