WebGL Tutorial
and more

sort, toSorted

撰写时间:2024-03-11

最新修订:2024-03-11

sort, toSorted

对数组排序。

  • sort直接在原数组上排序。
  • toSorted在原数组的一个副本上排序。原数组不受排序的影响。

原型

*[]sort
  • FunctioncompareFn
*[]toSorted
  • FunctioncompareFn

参数

callbackFn

回调函数。该回调函数接受2个参数。其原型如下:

numbercompareFn
  • *a
  • *b
a
定义排序规则的第一个元素。
b
定义排序规则的第二个元素。

回调函数compareFn期待一个返回值。这个返回值将作为a - b的结果来决定排列次序。因此:

  • 如果返回值小于0,则a - b < 0, 则a < b。因此a将排在b的前面。
  • 如果返回值等于0,则a - b = 0, 则a = b。因此ab的排列次序一样。则两者在数组中的位置保持不变。
  • 如果返回值大于0,则a - b > 0, 则a > b。因此a将排在b的后面。

返回值

sort返回经排序后的原数组的引用。

toSorted在原数组的一个副本上进行排序,返回该新数组。

说明

sort方法对数组进行原地排序,因此原来的数组变成经排序的数组。该方法的所返回的数组是原数组的引用。

toSorted在原数组的一个副本上进行排序,原数组未受排序影响。该方法所返回的数组是经排序后的新数组。

如果参数未指定回调函数,则将所有参与排序的数组元素都转换为字符串后再进行排序。具体详见下面的例子。

例子

原地排序

let nums = NumUtils.GetIntsInRange(1, 100, 5); console.log(nums); // [74, 72, 90, 21, 18]

上面,NumUtils的静态方法GetIntsInRange返回一个元素数量为5、数值范围为 [1, 100] 的数组。

let result = nums.sort(); console.log(result); // [18, 21, 72, 74, 90] console.log(nums); // [18, 21, 72, 74, 90] console.log(nums === result); // true

调用sort方法进行排序后,默认情况下对数组从小到大排序。

排序后,原来的数组也得以发生变化,所返回的数组是原来数组的引用。

在副本上进行排序

let nums = [5, 9, 2, 1, 8]; let result = nums.toSorted(); console.log(result); // [1, 2, 5, 8, 9] console.log(nums); // [5, 9, 2, 1, 8] console.log(nums === result); // false

调用toSorted方法进行排序,该方法返回已经排序的新数组,但原数组未受影响。

指定排序规则

默认情况下,sort方法是将回调函数返回值作为a - b的结果来决定排列次序,因此这是升序排序。如果我们要改为降序,则只需在回调函数中返回b - a的结果即可。

let nums = [1, 2, 3, 4, 5]; let sorted = nums.sort((a, b) => b - a); console.log(sorted); // [5, 4, 3, 2, 1]

在决定回调函数中到底是使用a - b还是使用b - a时,我们可以总结为一句话:视 a 为小数,b 为大数;被减数将排在左边。

因此如果我们希望升序排列,则将小数a作为被减数;如果希望降序排列,则将大数b作为被减数。

数组元素为对象时的排序

对于下面的数组:

let objs = [ {name: 'a', num: 3}, {name: 'b', num: 9}, {name: 'c', num: 5} ];

每个数组元素均为具体的对象。而对这种具体的对象,没有默认的排序规则。我们即可对其name属性进行排序,也可根据其num属性来进行排序。这完全由用户自行决定。

下面,我们对num属性进行降序排序:

let sorted = objs.sort((a, b) => b.num - a.num); console.log(sorted);

num属性参与比较运算。既然是降序,我们就将大数作为被减数。结果为:

[ {name: 'b', num: 9}, {name: 'c', num: 5}, {name: 'a', num: 3} ];

排序的默认行为

对于下面的数组:

let nums = [89, 150]; let sorted = nums.sort();

使用默认的升序排序。您认为结果是什么?既然是升序,结果当然是[89, 150]。但我们错了。

console.log(sorted); // [150, 89]

原因在于,这个世界太丰富多彩了,参与排序远不止只有整数而已。伟大且如爱因斯坦,尚不能统一宇宙4种之力。但雷人JavaScript却可以。在我们未指定回调函数时,它将所有参与排序的元素都统一转换为字符串,然后再根据字符串的UTF-16的码位值来进行排序。

上面,即使数组的两个元素均为整数,但经转换为字符串后,就成了["89", "150"],然后就开始逐字符比较了,"8""1"相比较,您认为哪个应排在先?

而更狠的是,在排序结果出来后,如果我们对结果产生质疑,欲查看结果数组中的数据类型时:

console.log(typef sorted[0]); // number

我们总是一次又一次地上当受骗。

因此,在调用sort方法时,我们应尽可能提供回调函数,以防止JavaScript擅自将数据类型悄悄转换为字符串来排序。

参见

  1. reverse

参考资源

  1. ECMA 262: Array Objects