Search code examples
javascriptarrayssortinginternet-explorer-11

Internet explorer 11 javascript array sort invalid results


I'm working on javascript dealer search functionality: http://www.example.com/kw_haendlersuche_bug

Try type "74564" in "Adresse" field and press enter. Result will be sorted list of dealers by distance.

On IE11 result will be different than on other browsers.

The key part of dealersearch_de_bug.js (line 166):

var c_sort = function(a, b) {
    return a.dist - b.dist;
};
markers.sort(c_sort);

But when I sort it twice - http://www.example.com/kw_haendlersuche

dealersearch_de.js line 166:

var c_sort = function(a, b) {
    return a.dist - b.dist;
};
markers.sort(c_sort);
markers.sort(c_sort);

Result is different and close to the result from other browsers.

What is going on?


Solution

  • One of the elements in your markers array has a NaN value for the dist property. (It's markers[482] in your current test case.) This is throwing off IE's sort() function - and in other browsers too.

    If you remove any such markers from your array before sorting, then it sorts correctly. You could do this with an if( ! isNaN(distance) ) test where you create the var current and push it to the markers array.

    I also agree with Curtis's comment about the libraries modifying Array.prototype - that can be dangerous because two libraries may step on each other. That isn't the cause of this particular problem though - the same error occurs if you sort the markers array in a vanilla test page with no libraries. Here is a simple example:

    <!doctype html>
    <html>
    <head>
        <title>Sort Test</title>
    </head>
    <body>
        <script>
            function log( array, text ) {
                document.write(
                    '[ ' + array.join(', ') + ' ] ' + text + '<br>'
                );
            }
    
            var array = [ 3, 9, NaN, 5, 4 ];
            log( array, 'original' );
            array.sort( function( a, b ) { return a - b; } );
            log( array, 'sorted' );
        </script>
    </body>
    </html>
    

    When I load this page in IE11 it displays:

    [ 3, 9, NaN, 5, 4 ] original
    [ 3, 4, 9, NaN, 5 ] sorted
    

    It also fails to sort correctly in Chrome:

    [ 3, 9, NaN, 5, 4 ] original
    [ 3, 9, NaN, 4, 5 ] sorted
    

    and Firefox:

    [ 3, 9, NaN, 5, 4 ] original
    [ 4, 5, NaN, 3, 9 ] sorted
    

    I suspect that your page was also not sorting correctly in the other browsers but was just "close enough" - unless for some reason the NaN value did not appear in those browsers.

    Why does the NaN value mess up sorting so badly? Well, sorting depends on being able to compare any two values of an array and get consistent results: less than, greater than, or equal.

    But NaN doesn't work like an ordinary number. You can compare any value with NaN and the result is always false, no matter what the comparison is - even if you compare with the same NaN value:

    console.log( NaN == NaN );  // false!
    

    Similarly if you add or subtract NaN in an expression, you always get NaN as a result. All of this wreaks havoc with a sort function, whether it uses comparisons or subtraction.