排序方法
数组中已经存在两个可以直接用来重排序的方法:reverse()
和sort()
。reverse()
方法会反转数组项的顺序。
试一试
const array = [1, 2, 3, 4, 5, 6]
result:
reverse()
方法的作用相当直观明了,但不够灵活,因此才有了sort()
方法` 。
在默认情况下,sort()
方法按升序排列数组项,即最小的值位于最前面,最大的值排在最后面。为了实现排序,sort()
方法会调用每个数组项的toString()
转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort()
方法比较的也是字符串。
示例代码
const array = [0, 1, 5, 10, 15];
array.sort();
console.log(array); // [0, 1, 10, 15, 5]
这样得到的结果并不符合数值排序的预期(5 应该小于 10)。因此sort()
方法可以接受一个比较函数作为参数,以便指定哪个值位于哪个值的前面。
比较函数接受两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数。下面是使用简单比较函数的一 个例子:
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
这个比较函数可以适用于大多数数据类型,可以把它当作参数传给 sort()方法,如下所示:
let values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values); // 0,1,5,10,15
在给 sort()方法传入比较函数后,数组中的数值在排序后保持了正确的顺序。当然,比较函数也 可以产生降序效果,只要把返回值交换一下即可:
function compare(value1, value2) {
if (value1 < value2) {
return 1;
} else if (value1 > value2) {
return -1;
} else {
return 0;
}
}
let values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values); // 15,10,5,1,0
此外,这个比较函数还可简写为一个箭头函数:
let values = [0, 1, 5, 10, 15];
values.sort((a, b) => (a < b ? 1 : a > b ? -1 : 0));
console.log(values); // 15,10,5,1,0
在这个修改版函数中,如果第一个值应该排在第二个值后面则返回 1,如果第一个值应该排在第二个值前面则返回 -1。交换这两个返回值之后,较大的值就会排在前头,数组就会按照降序排序。当然,如果只是想反转数组的顺序,reverse()更简单也更快。
注意
reverse()和 sort()都返回调用它们的数组的引用。
扩展的比较函数frequently-used
定义一个比较函数,用于对数组进行排序。也可接受一个对象的属性作为入参,实现对象数组根据某一属性进行排序的功能。
试一试
const array = [ 0, 5, 1, 3, 4, 6, 9, 8, 10 ]
排序结果 = [ 0, 1, 3, 4, 5, 6, 8, 9, 10 ]const array = [ { "name": "song", "age": 18 }, { "name": "xu", "age": 16 }, { "name": "zhang", "age": 20 }, { "name": "li", "age": 19 } ]
排序结果 = [ { "name": "li", "age": 19 }, { "name": "song", "age": 18 }, { "name": "xu", "age": 16 }, { "name": "zhang", "age": 20 } ]示例代码
/**
*
* @param {String | ''} propertyName 对象的属性,为空时取对象的第一个属性
* @param {Boolean} sort 升序(默认):true 降序:false
* @returns 返回一个比较函数
*/
const createComparisonFunction =
(propertyName, sort = true) =>
(object1, object2) => {
let value1 = null;
let value2 = null;
const typeObj1 = Object.prototype.toString.call(object1).slice(8, -1);
const typeObj2 = Object.prototype.toString.call(object2).slice(8, -1);
if (typeObj1 === "Object" && typeObj2 === "Object") {
if (propertyName) {
value1 = object1[propertyName];
value2 = object2[propertyName];
} else {
const firstProperty = Object.keys(object1)[0];
value1 = object1[firstProperty];
value2 = object2[firstProperty];
}
} else {
value1 = object1;
value2 = object2;
}
if (value1 < value2) {
return sort ? -1 : 1;
} else if (value1 > value2) {
return sort ? 1 : -1;
} else {
return 0;
}
};