Array.prototype.sort()
是 JavaScript 中一个十分常用的数组排序方法。但是这个方法在浏览器和 Node.js 中的排序效果可能会有所差异,在 ES11 中也加入了一些新的特性,因此需要我们注意一些技巧和注意事项以便更好地使用这个方法。本篇文章将会对这些细节进行详尽的讲解和示例代码演示。
基础使用
sort()
方法的基础用法很简单,它可以在原地对数组进行排序,即修改原数组而不返回新的数组。排序方法默认是按照 Unicode 码点进行排序的,如果希望按照数字大小,需要传入一个比较函数。
示例如下:
const arr = [3, 15, 2, 8, 1]; // 按照数字从小到大排序 arr.sort((a, b) => a - b); console.log(arr); // [1, 2, 3, 8, 15]
以上代码中,我们按照数字从小到大对数组进行排序,输出的结果为 [1, 2, 3, 8, 15]
。需要注意的是,sort()
方法会直接修改原数组,因此需要注意是否需要保留原数组。
注意事项
- 排序可能会改变元素顺序,如果需要保留元素顺序,需要通过浅拷贝或深拷贝来进行排序。
- 比较函数需要比较的是排序关键字,而不是对应的数组下标或值。
- 比较函数需要是稳定的,即对于相等的元素,排序后它们的顺序不会改变。
接下来,我们将通过示例代码来一一介绍这些注意事项。
1. 排序可能会改变元素顺序
示例代码如下:
const arr = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }, ]; // 按照 name 字段排序 arr.sort((a, b) => a.name.localeCompare(b.name)); console.log(arr); // 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
以上代码中,我们按照 name
字段排序,但是输出的结果与期望的不一样,原因是 sort()
方法直接改变了原始数组。我们可以通过浅拷贝来避免这个问题:
const arr = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }, ]; // 按照 name 字段排序 const newArr = [...arr].sort((a, b) => a.name.localeCompare(b.name)); console.log(arr); // 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ] console.log(newArr); // 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
以上代码中,我们通过浅拷贝创建了一个新数组 newArr
,并对其进行排序,同时保留了原数组 arr
的顺序。
2. 比较函数需要比较的是排序关键字
示例代码如下:
const arr = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }, ]; // 错误的比较函数 const compareFunc = (a, b) => a.name - b.name; arr.sort(compareFunc); console.log(arr); // 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
以上代码中,我们定义了一个错误的比较函数,试图按照 name
字段排序,但是输出的结果却没有进行排序。原因是比较函数应该是一个用来比较排序关键字,而不是对应的数组下标或值。我们需要改用如下的比较函数:
const compareFunc = (a, b) => a.name.localeCompare(b.name); arr.sort(compareFunc); console.log(arr); // 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
以上代码中,我们通过 localeCompare()
方法来比较字符串大小,实现了按照 name
字段排序。
3. 比较函数需要是稳定的
稳定排序是指在排序后,对于相等的元素,它们的顺序不会改变。如果不保证稳定性,排序后可能得到不同的结果,这对于一些需要排序的应用场景来说是无法接受的。在 JavaScript 中,sort()
方法默认是不稳定的。
示例代码如下:
const arr = [ { id: 1, name: 'Bob' }, { id: 2, name: 'Alice' }, { id: 3, name: 'Bob' }, ]; // 不稳定排序 arr.sort((a, b) => a.name.localeCompare(b.name)); console.log(arr); // 输出:[ { id: 2, name: 'Alice' }, { id: 1, name: 'Bob' }, { id: 3, name: 'Bob' } ]
以上代码中,我们试图按照 name
字段进行排序,但是得到的结果却是不稳定的。这个问题可以通过以下两种方法解决:
添加额外的排序关键字,比如按照
id
字段进行排序:arr.sort((a, b) => { const cmp = a.name.localeCompare(b.name); return cmp === 0 ? a.id - b.id : cmp; }); console.log(arr); // 输出:[ { id: 2, name: 'Alice' }, { id: 1, name: 'Bob' }, { id: 3, name: 'Bob' } ]
以上代码中,我们首先按照
name
字段进行排序,如果name
字段相同,则按照id
字段进行排序。这样可以保证排序的稳定性。使用稳定排序算法,比如归并排序:
const mergeSort = (arr, compareFunc) => { const merge = (left, right) => { let result = []; let l = 0; let r = 0; while (l < left.length && r < right.length) { if (compareFunc(left[l], right[r]) <= 0) { result.push(left[l]); l++; } else { result.push(right[r]); r++; } } return result.concat(left.slice(l)).concat(right.slice(r)); }; const sort = (arr) => { if (arr.length <= 1) { return arr; } const mid = Math.floor(arr.length / 2); const left = arr.slice(0, mid); const right = arr.slice(mid); return merge(sort(left), sort(right)); }; return sort([...arr]); }; arr = mergeSort(arr, (a, b) => a.name.localeCompare(b.name)); console.log(arr); // 输出:[ { id: 2, name: 'Alice' }, { id: 1, name: 'Bob' }, { id: 3, name: 'Bob' } ]
以上代码中,我们实现了一个归并排序算法,并将其应用到数组排序中,可以得到稳定的排序结果。
ES11 的新特性
在 ES11 中,sort()
方法添加了返回完整排序结果的功能。我们可以通过 Array.prototype.flatMap()
方法来实现这个功能。
示例代码如下:
const arr = [ { id: 1, name: 'Bob' }, { id: 2, name: 'Alice' }, { id: 3, name: 'Charlie' }, ]; // 新特性 const newSort = (arr, compareFunc) => arr.flatMap((value) => value).sort(compareFunc); console.log(newSort(arr, (a, b) => a.name.localeCompare(b.name))); // 输出:[ { id: 2, name: 'Alice' }, { id: 1, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
以上代码中,我们定义了一个 newSort()
方法,利用了 Array.prototype.flatMap()
方法的特性,返回了完整排序后的结果。
总结
Array.prototype.sort()
是 JavaScript 中的一个常用数组排序方法,但是在使用中需要注意排序对原始数组的影响、比较函数需要比较的是排序关键字、比较函数需要是稳定的等一系列问题。在 ES11 中,sort()
方法添加了新的返回完整排序结果的功能,可以更方便地使用。在实际应用中,我们需要根据具体场景选择不同的排序算法,并注意使用时的注意事项。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a24de3add4f0e0ffa6980f