在 JavaScript 中可以用 array.sort()
对数组进行排序。下面用它来对一些数字进行排序:
const numbers = [10, 5, 11];
numbers.sort(); // => [10, 11, 5]
呃。。。 numbers.sort()
的返回值居然是 [10,11,5]
,这是怎么回事?
为什么在不带参数的情况下调用 array.sort()
时,没有按预期排序?
1. array.sort()
不带参数
array.sort()
是数组实例上的一个方法,用于对数组进行适当的排序(在原始数组上原地操作)并返回排序后的数组。
当不带参数调用时,数组元素项会被转换为字符串并按字母序进行排序。
例如对下面的数组进行排序:
const names = ['joker', 'batman', 'catwoman'];
names.sort(); // => ['batman', 'catwoman', 'joker']
会按照按字母顺序排序:['batman','catwoman','joker']
。
但是,对数字调用该方法也会按照字母序进行排序:
const numbers = [10, 5, 11];
numbers.sort(); // => [10, 11, 5]
2. 带比较器的 array.sort()
不过 array.sort()
方法有一个可选参数:比较器函数。
const mutatedArray = array.sort([comparator]);
用这个函数可以控制排序过程中元素在数组中的排序方式。
如果 comparator(a,b)
的返回值为:
- 负数
<0
:那么a
会被放在b
之前 - 正数“> 0”:那么
b
会被放置在a
之前 0
:则比较元素的位置不变
为了正确地对数字按升序进行排序,应该用下面的比较器函数:
const numbers = [10, 5, 11];
numbers.sort((a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}); // => [5, 10, 11]
这样就可以正确地对数字进行排序了:[5, 10, 11]
。
在升序排列的数组中,较小的数字位于较大的数字之前。这是在编写比较器函数时需要维护的属性:
- 如果
a < b
:函数返回-1
,将a
放在b
的前面(例如5 <8
,因此5
在8
之前) - 如果
a> b
:函数返回1
,将b
放在a
之前(例如10> 3
,因此3
在10
的前面) - 如果
a === b
:顺序不变。
前面例子中的比较器函数有些长。我们可以这样简化:
const numbers = [10, 5, 11];
numbers.sort((a, b) => a - b); // => [5, 10, 11]
3. 对类型化数组排序
JavaScript 中的类型化数组包含特定类型的元素,例如 UInt8
:8位无符号整数,Float64
:64位浮点数等。而普通数组中的元素可以是任何类型,甚至可以是多种类型。
类型化数组的好处是,默认情况下它们的 sort()
方法对数字按升序进行排序。
如果不用比较器函数,那么利用类型化数组是对数字进行排序的好办法:
const numbers = [10, 5, 11];
const sortedNumbers = [...new Float64Array(numbers).sort()];
sortedNumbers; // => [5, 10, 11]
new Float64Array(numbers)
创建一个类型化数组的实例并初始化。
new Float64Array(numbers).sort()
按升序排序类型数组。在这里不需要比较器函数。
最后,展开运算符 [...new Float64Array(numbers).sort()]
把类型数组中的排序数字提取到常规数组中。
总结
如果不带参数调用 array.sort()
方法,将会按字母序对元素进行排序。所以不应该简单的用 array.sort()
对数字进行升序排序。
但是你可以指定一个比较器函数 array.sort(comparator)
来定制元素的排序方式。建议使用 numbers.sort((a, b) => a - b)
这种最简洁的方式对数字数组进行排序。