js Array sort实战排序全面讲解教程
作者:书签篮
一、sort()方法基础认知
1. 基本定义
sort() 是 JavaScript 数组原型上的内置方法,用于对数组元素进行排序,并返回排序后的原数组(注意:它是「原地排序」,会直接修改原始数组,而非返回新数组)。
2. 默认排序规则
sort() 方法如果不传入任何参数,会按照「字符串 Unicode 编码」进行排序,而非我们直觉中的数字大小排序,这是新手最容易踩坑的点。
示例:默认排序的表现
// 1. 字符串数组(符合直觉,按Unicode排序) const strArr = ["banana", "apple", "cherry", "Abc"]; strArr.sort(); console.log(strArr); // ["Abc", "apple", "banana", "cherry"] // 原因:Unicode 中大写字母编码(A-Z:65-90)小于小写字母(a-z:97-122) // 2. 数字数组(不符合直觉,按字符串Unicode排序) const numArr = [10, 2, 31, 4, 25]; numArr.sort(); console.log(numArr); // [10, 2, 25, 31, 4] // 原因:数字会被先转为字符串,"10"的Unicode编码小于"2",因此10排在2前面
二、sort()核心:比较函数(compareFunction)
要实现按数字大小、对象属性等自定义规则排序,必须给 sort() 传入一个比较函数((a, b) => {}),这是 sort() 方法的灵魂。
1. 比较函数的参数与返回值规则
比较函数接收两个必选参数 a 和 b(代表数组中任意两个待比较的元素,a 是后一个元素,b 是前一个元素),返回值的类型决定了排序结果:
| 比较函数返回值 | 排序规则 |
|---|---|
返回 负数(< 0) | a 排在 b 前面(升序逻辑) |
| 返回 0 | a 和 b 位置不变(稳定排序的关键) |
返回 正数(> 0) | a 排在 b 后面(降序逻辑) |
2. 数字数组的正/降序排序(最常用场景)
(1)数字升序排序
const numArr = [10, 2, 31, 4, 25]; // 比较函数:a - b 实现升序 numArr.sort((a, b) => a - b); console.log(numArr); // [2, 4, 10, 25, 31] // 原理:若a < b,a - b为负数,a排在b前面;若a > b,a - b为正数,a排在b后面
(2)数字降序排序
const numArr = [10, 2, 31, 4, 25]; // 比较函数:b - a 实现降序 numArr.sort((a, b) => b - a); console.log(numArr); // [31, 25, 10, 4, 2] // 原理:若b > a,b - a为正数,a排在b后面(即大的数排在前面)
三、常见场景实战排序
1. 字符串数组:忽略大小写排序
默认排序会区分大小写,通过将元素统一转为大写/小写后比较,可实现忽略大小写的排序:
const strArr = ["banana", "Apple", "cherry", "abc"];
strArr.sort((a, b) => {
const lowerA = a.toLowerCase();
const lowerB = b.toLowerCase();
if (lowerA < lowerB) return -1; // 升序
if (lowerA > lowerB) return 1;
return 0;
});
console.log(strArr); // ["Apple", "abc", "banana", "cherry"]
2. 字符串数组:按长度排序
const strArr = ["banana", "apple", "cherry", "a"];
// 先按长度升序,长度相同按Unicode升序
strArr.sort((a, b) => {
if (a.length !== b.length) {
return a.length - b.length; // 长度升序
}
return a.localeCompare(b); // 长度相同,按自然语言排序(比直接比较字符串更友好)
});
console.log(strArr); // ["a", "apple", "banana", "cherry"]
3. 对象数组:按单个属性排序
日常开发中最常用的场景,比如按用户年龄、商品价格排序:
// 用户数组
const users = [
{ name: "张三", age: 25, salary: 8000 },
{ name: "李四", age: 20, salary: 10000 },
{ name: "王五", age: 30, salary: 7000 },
];
// (1)按年龄升序排序
users.sort((a, b) => a.age - b.age);
console.log(users.map(u => u.name)); // ["李四", "张三", "王五"]
// (2)按薪资降序排序
users.sort((a, b) => b.salary - a.salary);
console.log(users.map(u => u.name)); // ["李四", "张三", "王五"]
// (3)按姓名自然语言排序(中文排序)
users.sort((a, b) => a.name.localeCompare(b.name, "zh-CN"));
console.log(users.map(u => u.name)); // ["李四", "王五", "张三"]
4. 对象数组:多条件排序
当第一个排序条件相同时,按第二个条件排序(比如:先按年龄升序,年龄相同按薪资降序):
const users = [
{ name: "张三", age: 25, salary: 8000 },
{ name: "李四", age: 20, salary: 10000 },
{ name: "赵六", age: 25, salary: 9000 },
{ name: "王五", age: 30, salary: 7000 },
];
users.sort((a, b) => {
// 第一个条件:年龄升序
if (a.age !== b.age) {
return a.age - b.age;
}
// 第二个条件:薪资降序(年龄相同时生效)
return b.salary - a.salary;
});
console.log(users.map(u => `${u.name}(${u.age}岁,${u.salary}元)`));
// 输出:
// ["李四(20岁,10000元)", "赵六(25岁,9000元)", "张三(25岁,8000元)", "王五(30岁,7000元)"]
5. 包含特殊值(null/undefined)的数组排序
sort() 会自动将 undefined 排到数组末尾;null 转为数字是 0,可手动处理其排序位置:
const mixedArr = [10, null, 5, undefined, 3, null, 8];
mixedArr.sort((a, b) => {
// 处理undefined:直接排到末尾
if (a === undefined) return 1;
if (b === undefined) return -1;
// 处理null:按0参与数字升序排序
return (a ?? 0) - (b ?? 0);
});
console.log(mixedArr); // [null, null, 3, 5, 8, 10, undefined]
四、进阶知识点:稳定排序
1. 稳定排序的定义
如果数组中两个相等的元素(按比较函数判断返回 0),在排序前后的相对位置保持不变,这种排序就是「稳定排序」。
2.sort()的稳定性
- ES6(ECMAScript 2015)及以后:
sort()方法实现了稳定排序(不同浏览器内核实现一致)。 - ES6 之前:
sort()是不稳定排序,不同浏览器表现可能不同。
示例:验证稳定排序
// 商品数组:按价格升序(价格相同的商品,保持原有相对位置)
const goods = [
{ name: "商品A", price: 50 },
{ name: "商品B", price: 30 }, // 先出现
{ name: "商品C", price: 50 },
{ name: "商品D", price: 30 }, // 后出现
];
// 按价格升序排序
goods.sort((a, b) => a.price - b.price);
console.log(goods.map(g => g.name)); // ["商品B", "商品D", "商品A", "商品C"]
// 结果:价格30的商品B仍在商品D前面,价格50的商品A仍在商品C前面,验证了稳定排序
五、常见误区与避坑技巧
1. 误区1:忽略「原地排序」,误认返回新数组
sort() 会修改原始数组,返回的是原始数组的引用,而非新数组。如果需要保留原始数组,应先拷贝数组再排序。
避坑示例:
const originalArr = [10, 2, 31]; // 先拷贝数组(推荐使用扩展运算符或slice(),浅拷贝即可) const sortedArr = [...originalArr].sort((a, b) => a - b); console.log(originalArr); // [10, 2, 31](原始数组未被修改) console.log(sortedArr); // [2, 10, 31](排序后的新数组)
2. 误区2:数字排序不传入比较函数
新手常直接对数字数组使用 sort(),导致排序结果不符合预期,必须传入 (a, b) => a - b(升序)或 (a, b) => b - a(降序)。
3. 误区3:比较函数返回非数字类型
比较函数的返回值应是数字(负数/0/正数),若返回布尔值或其他类型,会被隐式转为数字(true→1,false→0),可能导致排序异常。
错误示例 vs 正确示例:
const numArr = [10, 2, 31]; // 错误:返回布尔值,排序结果不可靠 numArr.sort((a, b) => a > b); // 正确:返回数字,排序结果稳定 numArr.sort((a, b) => a - b);
4. 误区4:中文排序直接使用字符串比较
直接用 a > b 比较中文,会按 Unicode 编码排序,不符合中文的拼音/笔画排序逻辑,应使用 localeCompare() 并指定中文环境。
正确示例:中文拼音排序
const chineseArr = ["张三", "李四", "王五", "赵六"];
// localeCompare("zh-CN"):按中文拼音排序
chineseArr.sort((a, b) => a.localeCompare(b, "zh-CN"));
console.log(chineseArr); // ["李四", "王五", "张三", "赵六"]
六、sort()方法的性能说明
sort() 的底层排序算法并非固定(由浏览器内核实现):
- Chrome/V8 引擎:对于小型数组(长度≤22)使用「插入排序」,大型数组使用「快速排序的变种(TimSort/QuickSort)」,平均时间复杂度为
O(n log n)。 - Firefox 引擎:使用「归并排序」,时间复杂度
O(n log n)。
日常开发中无需关注底层实现,只需关注排序规则和稳定性即可,其性能足以满足绝大多数业务场景。
总结
sort()是原地排序方法,会修改原始数组,需保留原数组时应先拷贝([...arr]/arr.slice())。- 默认按字符串 Unicode 排序,数字/对象排序必须传入比较函数,核心规则是「返回负数a在前、返回正数a在后、返回0位置不变」。
- 常见场景:数字正/降序(
a-b/b-a)、对象多条件排序、中文排序(localeCompare("zh-CN"))。 - ES6 及以后
sort()是稳定排序,特殊值(undefined)默认排末尾,使用时需规避非数字返回值等误区。
到此这篇关于js Array sort实战排序全面讲解教程的文章就介绍到这了,更多相关js Array sort排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
