Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery.each implementation differs from native Array.forEach

Does anyone why is the otherwise excellent jQuery.each function is designed differently from the (now) native Array.forEach? F.ex:

var arr = ['abc','def'];
arr.forEach(function(entry, index) {
    console.log(entry); // abc / def
});

This makes absolute sense. But jQuery chose to put the index as first argument:

$.each(arr, function(index, entry) {
   console.log(entry);
});

Does anyone know the reasoning behind this design decision? I have always used $.each extensively, but it always bugged me that the index was the first argument as it is rarely used. I know jQuery implemented a direct reference through this but it’s very confusing if you do:

​var arr = ['abc','def'];
$.each(arr, function() {
    console.log(this === 'abc'); // false both times, since this is a String constructor
});​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

Not that it bothers me so much, I prefer to use native polyfills for the most common new array functions, but I have always been curious about the design decision. Maybe it was made in older times before browsers implemented native forEach and legacy support prevented them from changing it, or...?

Or maybe, it is designed this way because is can be used on native objects too, than then it "makes sense" to put the key before value in the callback...?

Sidenote: I know underscore.js (and maybe other libraries) does it the other way around (more similar to the native function).

like image 577
David Hellsing Avatar asked Oct 26 '12 23:10

David Hellsing


3 Answers

Well, I guess we'd have to ask Mr. Resig himself for an explanation on this. Fact is, that ECMAscript 262 edition 5 wasn't very widespread the time jQuery was designed and developed, so this definitely comes into play. And since it was designed like so, they didn't want to change it later and break all existing code.

In fact, its much more likely that you want to access an element with a higher priority, than the index of it when looping an Array. So, to me there is no reasonable explanation why you would pass in the index first into the callbacks.

Be assured, if jQuery was invented today, they would follow the native implementation behavior.

On the other hand, if it bugs you too much you can simply create a shortcut and use the native Array.prototype.forEach to iterate your jQuery wrapped sets:

var forEach = Function.prototype.call.bind( Array.prototype.forEach );

forEach( $('div'), function( node ) {
    console.log( node );
});

..and for standard Arrays, just go with their native prototype.

while implementation conditional return false/true,we must know what part work in which manner. When you use return false with condition in Array.prototype.forEach it treated as continue, but When you use return false, with condition in $.each it treated as break statement.

var listArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
var arr1 =[];var arr2=[];
var rv = true;
listArray.forEach(function(i, item) {
  if (i == 5) {
    return rv = false;
  }
 arr1.push(i)
  return rv;
});
var listArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
jQuery.each(listArray, function(i, item) {
  if (item == 5) {
    return rv = false;
  }
  arr2.push(i)
});
  console.log("forEach=>"+arr1)
  console.log("$.each=>"+arr2)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
like image 165
jAndy Avatar answered Nov 08 '22 16:11

jAndy


This actually got mentioned at the last jQuery conf; unfortunately I don't remember the details, but if you watch enough of the video from it I imagine you can find it (I think it was during Q&A after the keynote, but don't quote me on that). Anyhow someone (I don't think it was Resig himself, but another senior jQuery org member) basically said "jQuery has some things that we all know are problematic ("each" being one of the examples they gave) but there are millions of sites out there that now rely on that problematic behavior so we can't change it now."

So in essence, the answer is that they made a bad decision (Resig is an INCREDIBLE programmer, but even he isn't perfect) and now everyone using jQuery has to suffer for the rest of time because the library maintains relatively high backward compatibility in new versions (and let's face it, that's a good thing: you don't want to have to re-write your whole site every time you upgrade jQuery).

It's also worth mentioning that the Underscore library does have a each method with the same signature as the built-in each. In fact, Underscore's version actually uses the built-in version if present, for better performance, relying only its version if the browser doesn't support the built-in each. Since jQuery objects are just arrays, you can easily use them with _.each, and since Underscore has a lot of other functionality missing from jQuery it's an excellent library to complement jQuery.

like image 6
machineghost Avatar answered Nov 08 '22 18:11

machineghost


Well i agree it makes more sense to have the key second but you have to keep in mind $.each can be used with an object or an array and in the case of the object you may want the keys since they have meaning.

like image 1
prodigitalson Avatar answered Nov 08 '22 18:11

prodigitalson