前端知识学习

在 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) 这种最简洁的方式对数字数组进行排序。