一.前言
上一篇 blog 005 V8的sort实现中,我们简单聊了聊,引擎中的排序算法的思想和实践。但具体细节我们其实没有展开。
本文中,我们直接来 sort 函数相关的 JS实践 。
二.sort()默认函数
你猜下面函数的运行结果是什么?
[7,-2,2,-7,-3].sort()
// 会是 [-7, -3, -2, 2, 7] 吗?
下面来揭晓答案!
肯定不会符合你的预期啦!
答案是:
[-2, -3, -7, 2, 7]
为什么呢?
官方定义,MDN Array.prototype.sort(),sort()方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。
arr.sort(compareFunction)
// compareFunction: 用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的 Unicode 位点进行排序。
// 返回值: 排序后的数组。请注意,数组已原地排序,并且不进行复制。
定义略微有点长,且晦涩。
通俗点说,sort() 默认等价于sort((a,b)=>a.toString().localeCompare(b))。
MDN String.prototype.localeCompare(): 如果引用字符存在于比较字符之前则为负数; 如果引用字符存在于比较字符之后则为正数; 相等的时候返回 0 .
我们来解释下上面的案例:
对于V8来说,-7,它会理解成两个token:-、7。
-的码点是在数字之前的,所以负数一定在最前方,即 数组前三位一定是-2,-3,-7。
码点感兴趣的可以阅读 阮一峰 Unicode与JavaScript详解
接下来我们看一下顺序,都有- ,可以忽略,简化为2,3,7 比较顺序,所以顺序就是2,3,7
最后排好顺序,再加上-即可。
所以,解决方案:
[7,-2,2,-7,-3].sort((x, y) => x - y)
// [-7, -3, -2, 2, 7]
所以,基于这个,在看个例子
[1, 111, 2, 3].sort() // [1, 111, 2, 3]
'1'.localeCompare('111') // -1
'2'.localeCompare('111') // 1
因为我们提到 compareFunction: 如果省略,元素按照转换为的字符串的各个字符的 Unicode 位点进行排序.
111和2比较,前者第一个字符1的码点位于后者前面,所以111在2前面。
三.sort(compareFunction)的compareFunction
下面的代码,我们希望运行结果应该是: 连续的数字升序排列。
var arr = [
{value: 3},
{value: undefined},
{value: 2},
{value: undefined},
{value: 5},
{value: 1},
{value: undefined},
{value: 4}
];
res = arr.sort((x, y) => x.value - y.value).map(x => x.value);
console.log(res);
它会符合预期吗?
显然不会。
真实运行结果是:
// [ 3, undefined, 2, undefin