背景
sort方法用来对数组元素进行排序。但是浏览器实现可能有不同,已经两次踩到坑了,因此记录一下。
规范
ecma-262制定的排序规则:
使用两个参数x和y唤起排序
1、如果x、y都是undefined,返回 +0
2、如果x为undefined,返回 1
3、如果y未undefined,返回 -1
4、如果定义了排序方法
a、设v = ToNumber(comparefn(x, y))
b、如果v是NaN,返回 +0
c、返回v
5、设xString = ToString(x)
6、设yString = ToString(y)
7、如果xString < yString,返回 -1
8、如果yString < xString,返回 1
9、返回 +0
当
返回1的时候,x应排在y后面
返回0的时候,x、y位置不变
返回-1的时候,x应排在y前面
坑1:排序不一定是稳定的,即相等的两个元素不一定会保持在原来的位置。排序方法返回0的两个元素仍可能交换位置,如chrome浏览器的排序实现,在数组长度小于等于10的时候就使用插入排序法,没有什么问题,但是数组大于10的时候就会使用快速排序,在比较起始值和中值的时候,排序方法返回值大于和等于0的时候都会对调位置。
我遇到的情况是,需要对会员卡数组进行两个维度的比较排序,数组元素对象可能包含次卡或者折扣属性,次卡排在折扣卡前面,折扣卡按折扣大小排序。当时我写的排序方法为:(a, b) => { return (a.discount && b.times) || a.discount > b.discount },后来发现有时次卡没有排在折扣卡前面,改为:(a, b) => { if ((a.discount && b.times) || a.discount > b.discount) return 1; return -1; })
坑2:如上面排序规则第4条a,按标准需要把排序方法返回值转为Number类型,但是有些浏览器版本如Safari10并没有实现这一步,如果排序方法返回true/false布尔值而不是Number类型,元素位置就不会进行调整。