The array returned by .get() does have its elements in the correct order.
The bug is actually in your code:

>         for(ai in arr) { txt.push(arr[ai].innerHTML); }

You can't use a "for...in" loop on an array and expect to get consistent
results. The order of enumeration is implementation dependent. It may be in
numerical order, or it may be in the order the elements were added to the
array, or anything else. You may note that you get different results in IE7
and Firefox 3.

A for...in loop also enumerates non-array-element properties of the array.
For example, if any JavaScript code or library adds methods to
Array.prototype (and many libraries do this), those methods will also be
enumerated in your for...in loop.

A numeric for loop would work correctly:

    for( i = 0, n = arr.length;  i < n;  ++i )
        txt.push(arr[i].innerHTML);

The reason .each works correctly is that it does a numeric for loop like
that.

What changed in 1.2.6?

The code you found in makeArray does assign the elements into the correct
array indices but it does them backwards chronologically. IOW, makeArray is
assigning elements in this order:

    ret[2] = array[2];
    ret[1] = array[1];
    ret[0] = array[0];

That's perfectly valid code, of course, but a for...in loop on the "ret"
array will give inconsistent results. A correct numeric for loop will not be
bothered by that.

In 1.2.3 the loop in makeArray ran in forward order:

    ret[0] = array[0];
    ret[1] = array[1];
    ret[2] = array[2];

All that said, I wonder if it wise for makeArray to be running this loop in
reverse, just because of problems like this. Would be that much less
efficient to run the loop in forward order?

There's some further discussion in the ticket for this code change:

http://dev.jquery.com/ticket/2619

-Mike

> From: joelarson
> 
> I have just noticed that the order of elements returned by 
> .get() seem to have been reversed in 1.2.5 and 1.2.6.  
> Interestingly, each seems to run in the expected order (from 
> first element to last as encountered in the document).  To 
> demonstrate:
> 
> ----------------------------------
> <script src="http://jqueryjs.googlecode.com/files/jquery-1.2.5.js";></
> script>
> <span>1</span><span>2</span><span>3</span>
> <script language=JavaScript><!--//
>     $(function() {
>         var arr=$("span").get();
>         var txt=[];
>         for(ai in arr) { txt.push(arr[ai].innerHTML); }
>         alert("via get(): "+txt.join(","));
>         $("span").each(function(i,o) { alert("via each #"+i
> +".html="+o.innerHTML); });
>     });
> //--></script>
> ----------------------------------
> 
> Your first alert will show "via get(): 3,2,1".  Your next 3 
> alerts will show 1,2,3 in order as the innerhtml.
> 
> This seems to come from around line 1133 of the 
> jquery-1.2.5.js (around the same line in 1.2.6), where the 
> way the array is filled in makeArray is:
> 
> ----------------------
> while( i )
>   ret[--i] = array[i];
> ----------------------
> (which obviously builds a backwards return array)
> 
> whereas in jquery-1.2.4.js line 1125 is code:
> 
> ----------------------
> for ( var i = 0, length = array.length; i < length; i++ )
>   ret.push( array[ i ] );
> -----------------------
> 
> It seems to me that the get() must return the elements in the 
> document specified order.  Even though this is not spelled 
> out in the specification it seems to be the only rational behavior.
> 
> If my assumption is correct then, the easiest way to fix is to insert:
> 
> ------------
> ret.reverse();
> ------------
> 
> at line 1141 of 1.2.6.js (or equivalent in future 1.2.7).
> 
> 
> 
> I have not found any posts on this or notes anywhere, but it 
> is possible I do not know every relavent area to check.  So 
> don't beat me up if this is known or desired behavior-- just 
> tell me where I should have looked.  Thanks!
> 

Reply via email to