分类: javascript      标签:sort     

关于Array中的sort()

sort() 实现的功能很简单,就是对数组进行简单的排序。但在自定义的情况下,它根据传入的函数参数返回结果判断,这个结果要求是一个数字,但在不同浏览器下,自定义会产生一定的偏差,甚至会导致IE下代码终止执行。基于此,对不同浏览器进行测试探讨。

概述

在原数组中对数组元素进行排序,没有创建新的数组。

不带参数调用

不带参数调用,将按照字符编码顺序对数组中的元素进行排序。即先把数组元素转换为字符串,再进行比较排序。这个排序默认是升序的,字符编码越大的越排到后面。但这里面有一个特例:undefined,它会一直被排到最后,不参与字符串字符编码值的比较(null/true/false 会被转换成对应的字符串,然后参与比较)。

var arr = [3, 14, 1, null, false, undefined, 'uzdefined',
           {x: 12},
           [2, 3],
           function(){}];
arr.sort();
// arr: 
// [1, 14, [2,3], 3, {x:12}, false,
//  function(){}, null, "uzdefined", undefined]

这个例子中包含了我们日常用到的所有类型,除了 undefined ,其他都遵循了比较转化成字符串后的编码值。其中 [2, 3] 字符串化后是 "2,3"{x: 12} 字符串化后是 "[object Object]",函数字符串化后就是函数定义本身。

传入比较函数

sort() 接受一个函数作为比较函数,这个函数接受两个值作为参数,比较它们,返回一个数字表明它们的相对顺序。

接受的两个参数 a、b,比较结果如下:

undefined 即使是在使用了自定的排序中,也会一直排到最后,因为 undefined 不会传递给排序函数

var arr = [5,null,undefined,13];
arr.sort(function(a,b){
    console.log(a, b, '=', a - b);
    return a - b;
});
console.log(arr);
// 输出:
// 5 null "=" 5
// 5 13 "=" -8
// [null, 5, 13, undefined]

从这个例子中,可以看到,null 在运算中会被自动转换成数字 0 ,参与排序运算,但 undefined 根本就没有被传入比较函数中。

特别注意

排序不稳定性

JavaScript中的这个排序方法是不稳定的,即对相等的元素,两个元素的顺序不一定是一致的。

当比较函数返回 0 时,ECMAScript标准并没有指定是否两个元素不交换顺序,因此,并不是所有浏览器实现都保证保持原来的顺序(比如2003版本的Mozilla)。

这个特点对针对对象的某一项属性排序时,可能有影响。比如:

var arr = [
    {name: 2, content: 34},
    {name: 2, content: 35},
    {name: 2, content: 36},
    {name: 2, content: 37}
];

这时只针对每个数组元素的 name 属性排序,因为值都是 2,因此排序后的新数组,可能会受不稳定性的影响,导致新的顺序中的 content 不能再按顺序排列。

这个问题应该只针对老版本的实现,起码在 IE6 下还没有测试出这个问题。

关于更老版本可能带来的问题,参见 Mozilla关于sort的技术文档

比较函数返回非数字值

自定义比较函数要求返回一个数字,但是如果返回的结果是一个非数字时,多数浏览器都能继续工作,返回的排序结果不再能保证正确顺序。但是在IE系列中,还是有些特别。IE6 中,只要返回的内容不能转换成数字,就会终止代码的执行。(测试中,最高只有IE8版本的机子,IE7/8中,只要非NaN的返回值如果不能转换成数字,代码也会终止,但是升级IE8到IE9后,通过开发者工具模拟 IE7/8,这个现象消失了,不过IETester中的模拟仍然能够重现。IE9无论返回什么都能继续执行程序)

因此,针对比较函数,请确保返回值一定是一个数字,否则可能不能按预期排序,甚至在 IE 尤其是 IE6 代码可能停止而不报错。

性能

暂不讨论这个方法的性能问题,猜想或许有原生的效率优势。

总结

针对 sort() 有以下几点要注意:

排序测试部分代码示例:http://jsfiddle.net/calefy/m9ztx/

-EOF-


blog comments powered by Disqus