你应该知道的JS(数组)-Array.sort
基础语法
_定义:_sort() 方法用于对数组的元素进行排序。
语法:array.sort(sortfunction)
参数:
参数 | 描述 |
---|---|
sortfunction
| 可选。规定排序顺序。必须是函数。 |
返回值:
Type | 描述 |
---|---|
Array | 对数组的引用。请注意,数组在原数组上进行排序,不生成副本。 |
示例用法
1. 不传参
let arr1=[3,2,1];
arr1.sort() // [1, 2, 3]
let arr2=[30,20,100];
arr2.sort() // [100, 20, 30] ???
奇怪不?100在20前面。这不是出错了,而是因为sort方法在你不传参数时会给你一个默认参数(下图为v8引擎源码的sort代码,comparefn为sort方法参数)。默认comparefn方法会把数组内容转为string类型(下图720,721行)。
在js中,string类型进行比较时会依次比较两个字符串对应的字符编码值。字符串“100”和“20”比较时会先比较“1”和“2”,1<2,所以结果就是字符串“100”小于字符串“20”。这里我想起来去年一个朋友问我的问题。他碰到一个单看代码貌似没有错误的bug,这个bug导致他在计算一些优惠券数量时发生类似10<9的意外情况,但是完全找不到问题在哪。我听完之后第一反应就是这个问题导致的,于是在测试字符串比较情况后,发给他测试代码。他debugger之后发现果然是数据类型问题。关于关系操作符我也有很多想聊的,但是今天毕竟是说数组的sort方法,在此不做展开。
2. 传参
排序函数sortfunction规则:
-
传两个形参
-
当返回值为正数时,交换传入两形参在数组中位置
let testArr=[1,3,2,4] testArr.sort((a,b)=>{ console.log(a,b) }) // 3 1 // 2 3 // 4 2
这里发现两个参数,前面的参数a实际上传入的是数组的后一项,与我们的直觉不同。很奇怪,那我们再看一下v8的数组源码
//这里是v8的sort核心排序的一部分,sort核心是快排。但是当快排的片段长度(to-form<10)会调用下面
//的插入排序方法。
var InsertionSort = function InsertionSort(a, from, to) {//a:待处理数组,from,to:处理片段范围
for (var i = from + 1; i < to; i++) {
var element = a[i];
for (var j = i - 1; j >= from; j--) {
var tmp = a[j];
var order = comparefn(tmp, element);
if (order > 0) {
a[j + 1] = tmp;
} else {
break
}
}
a[j + 1] = element;
}
}
看起来又没有问题。
//规则测试
let arr=[1,3,2,4]
arr.sort((a,b)=>0) // [1, 3, 2, 4] 不变
arr.sort((a,b)=>false) // [1, 3, 2, 4] 不变
arr.sort((a,b)=>1) // [1, 3, 2, 4] 不变
arr.sort((a,b)=>-1) // [4, 2, 3, 1] 交换位置
这里又很奇怪结果为正数不变,负数反而交换位置,与各网站的sort定义及源码都不一样。这个结果与定义
相反加上参数a,b顺序也与定义相反。负负得正,反而正常了。神奇!测试了半天确定我都没有弄错,
希望有知道的同学能够评论一下给我解惑。感谢!
//常用方式
let testArr=[1,3,2,4]
testArr.sort((a,b)=>a-b) // [1, 2, 3, 4] 升序
testArr.sort((a,b)=>b-a) // [4, 3, 2, 1] 降序
//对象数组
let objArr=[{age:25,name:'lgc'},{age:18,name:'loli'},{age:35,name:'uncle'}]
objArr.sort((a,b)=>a.age-b.age) // [{age:18,name:'loli'}, // {age:25,name:'lgc'}, // {age:35,name:'uncle'}]
总结及注意点:
1. sort方法会改变原始数组
2. 不传参时,数组的项会被转为字符串再进行比较
3. 排序函数每次传入数组的两个项进行比较,返回值为正数(存疑)时,交换两项的位置。其他情况不变。
转载自:https://juejin.cn/post/6871145617579343885