July 25 2009

Array.sort browser differences

WebKit says, "Boolean comparison functions? What the farmer?"Javascript’s Array class has a handy function, sort(). You just pass in any comparison function, and it will sort the array for you. Therefore, the following code works:

[3,1,4,2,5].sort(function(a,b) {
    return a > b;
});

Or rather, it works in Firefox: it sorts the array to [1,2,3,4,5]. In IE, it seems to work at first glance: the 2 is out of place in the output. In Safari and Chrome, nothing changes at all. That’s because Webkit requires the comparison function to return an integer rather than a boolean, otherwise it does nothing with no error. The correct code is:

[3,1,4,2,5].sort(function(a,b) {
    return a - b;
});

This will work in all browsers. Something to keep in mind if you ever get a “Sorting doesn’t work in WebKit” bug and are scratching your head.

7 Comments

Related Posts

7 Comments

  1. Boris
    July 25, 2009
    2:54 pm

    The sorting stability of Array.sort also depends on the browser’s implementation. IE’s Array.sort is stable but Firefox pre-3.5 makes no such guarantees. Even more annoyingly, I think Safari’s Array.sort is stable, but Chrome’s isn’t (don’t quote me on this one though).

    I’ve hit a few obscure problems because of this when trying to double sort objects.

  2. Allen
    July 26, 2009
    10:01 am

    That’s frustrating. Yet more reasons to use a framework that abstracts this out, I guess.

  3. Greg Burghardt
    January 29, 2010
    6:42 am

    The custom function passed to the Array.prototype.sort method has been wrong on almost every website I’ve come across. This custom function should determine if a is greater than b, a is less than b, OR a and b are equal.

    http://msdn.microsoft.com/en-us/library/4b4fbfhk%28VS.85%29.aspx

    Only then will the custom sort function work correctly cross-browser. It was Microsoft’s documentation that shed some light on this. It works cross browser in my testing on Firefox (Gecko), IE (Trident), Safari (Webkit/Apple) and Chrome (Webkit/Google).

    myArray.sort( function( a, b ) {

    if ( a === b ) return 0; // a and b are equal

    if ( a < b ) return -1; // a is less than b, b comes first

    else return 1; // a is greater than b, a comes first

    } );

    The number you return for "a is greater than or less than b" will depend on whether you are sorting by ascending or descending order.

    The function passed to Array.sort should return:

    0 (zero) if a and be are EQUAL.

    1 if a is GREATER than b

    -1 if a is LESS than b

    Returning a boolean value just tells the browser less-than or greater-than, and omits equal-to. Since many browsers are written in C, the number -1 is logically equivalent to true. not only is returning a boolean value omitting a possible value for the sort (a and b are equal), it could be interpreted incorrectly depending on the programming language the browser is written in.

    Always return 0, 1 or -1 from Array.sort. Never return a boolean value.

  4. Greg Burghardt
    January 29, 2010
    6:46 am

    As an aside, I have a theory why it seems to work on Firefox and no other browser. It seems that Firefox only calls the function you pass to Array.sort when a and b are NOT equal, and therefore only requires a test for greater-than or less-than. By how all other browsers behave, they seem to call the function you pass to Array.sort EVERY time, and leave it up to the function to determine equivalency, greater-than or less-than.

  5. Allen
    January 29, 2010
    10:36 am

    Interesting insight Greg. Although my solution of returning (a – b) doesn’t return strictly {-1, 0, 1}, it does work in all browsers I tried since they seem to be testing for <0, 0, and >0.

  6. Greg Burghardt
    February 1, 2010
    6:26 am

    The only thing that I see as an issue with using subtraction is how you subtract non numbers? When sorting strings, the minus sign will cause the browser to convert the strings into numbers, and if you are sorting non numeric strings, you will be performing subtraction with NaN (Not a Number) values. Subtracting “a” from “b” probably works in your code because you are sorting numbers. Things get a little trickier when you have to sort booleans, strings, and dates. For this reason I highly recommend explicitly testing for less-than, equality, and greater-than, and then returning -1, 0 or +1.

    I’m not in any way trying to argue. I just got done spending a week banging my head against the wall with client side sorting, and thought I’d save you a few dents and bruises. :)

  7. Alain Saint-Etienne
    March 16, 2010
    6:53 am

    David Flanagan’s “JavaScript, The Definitive Guide” (O’Reilly, 3rd Edition, 1998(!)) states that the custom sort function should return 0 (zero) if a and b are equivalent, “a number less than zero” if a should appear before b, or “a number greater than zero” if a should appear after b.

    It seems to me the issue is not different implementations across browser, as they all seem to behave as expected if a number is returned.

    I’m afraid we developpers just got accustomed to coding by the browser implementations (and their specific shortcuts, like accepting that function returning a boolean), rather than coding by the book.

    It’s a nice outcome that renewed browser competition pushes us back to reading the specs, and coding in a little more… standard-compliant way.
    We can’t expect browser vendors to provide standard-compliant code, if they have to deal with non-standard web developer code, can we ?

Comments feed
TrackBack URL
Avatars by Gravatar

What do you think?