JavaScript数组sort方法详解:从默认排序到自定义排序
本文详细介绍JavaScript中Array.sort()方法的默认行为及潜在陷阱,特别是数值排序时因字符串比较导致的错误。通过示例演示如何传入自定义比较函数实现数字升序、对象属性排序以及XML节点排序,帮助开发者灵活掌握数组排序技巧。
JavaScript数组sort方法详解:从默认排序到自定义排序
在日常业务开发中,数组(Array)是高频使用的数据类型,因此对数组进行排序也是常见需求。除了手动编写循环遍历来排列数据外,利用JavaScript数组内置的sort方法更为便捷,这也体现了原生API的高效性。
举个栗子
1、举个栗子
数组提供了两个直接用于排序的方法:reverse()和sort()。由于reverse()的功能较为单一,sort()方法因此成为更常用的选择。默认情况下,sort()方法会按升序排列数组元素。
var arr=[1,3,5,9,4];
console.log(arr.sort());
// 输出: [1, 3, 4, 5, 9]
此时数据按从小到大排列,结果符合预期;然而,当将数组修改为var arr=[101,1,3,5,9,4,11]并再次调用sort()方法打印结果时,情况发生了变化。
var arr=[101,1,3,5,9,4,11];
console.log(arr.sort());
// 输出: [1, 101, 11, 3, 4, 5, 9]
观察发现,101和11被排在了3的前面。这是因为sort()方法在比较时会先调用数组每一项的toString()方法将其转换为字符串,随后基于字符串进行比较,即使数组元素原本都是数值类型,sort()依然执行的是字符串比较逻辑。
那么字符串具体是如何排序的呢?它是依据字符串的Unicode编码值从小到大进行排列的。为了验证这一点,我们可以尝试打印数组中每一项对应的Unicode编码。
...
// 转码方法
function getUnicode (charCode) {
return charCode.charCodeAt(0).toString(16);
}
// 打印转码
arr.forEach((n)=>{
console.log(getUnicode(String(n)))
});
// 输出: 31 31 31 33 34 35 39
结果显示,数字1、101和11转换为字符串后的Unicode编码值均为31(十六进制),这解释了为何它们在排序中处于相同的位置。
传入比较函数以指定顺序
2、传入比较函数以指定顺序
既然默认行为不符合预期,该如何解决?sort()方法允许接收一个比较函数作为参数,从而指定元素的前后顺序。
该比较函数(compare)接收两个参数:若第一个参数应排在第二个参数之前,则返回负数;若两个参数相等,则返回0;若第一个参数应排在第二个参数之后,则返回正数。
function compare(value1,value2){
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else{
return 0;
}
}
我们将此比较函数传递给sort()方法,对arr数组进行重新排列,打印结果如下:
var arr=[101,1,3,5,9,4,11];
console.log(arr.sort(compare));
// 输出: [1, 3, 4, 5, 9, 11, 101];
可以看到,此时数组已正确按从小到大顺序排列。
对象数组的排序
3、对象数组的排序
sort()方法通过传入比较函数可以排序数字数组,但在实际开发中,我们常需对对象数组的特定属性(如id、年龄等)进行排序。如何实现这一需求?
解决该问题的方法是定义一个高阶函数,接收属性名作为参数,并返回一个用于比较的函数。JavaScript中函数是一等公民,不仅可以作为参数传递,还可以作为返回值返回,这种灵活性使得代码编写更加简洁。具体代码如下。
function compareFunc(prop){
return function (obj1,obj2){
var value1=obj1[prop];
var value2=obj2[prop];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else{
return 0;
}
}
}
定义一个包含用户信息的数组users,调用sort()方法并传入由compareFunc(prop)生成的比较函数,打印输出结果:
var users=[
{name:'tom',age:18},
{name:'lucy',age:24},
{name:'jhon',age:17},
];
console.log(users.sort(compareFunc('age')));
// 输出结果
[{name: "jhon", age: 17},
{name: "tom", age: 18},
{name: "lucy", age: 24}]
默认情况下,调用sort()且不传比较函数时,它会调用每个对象的toString()方法来确定顺序。而当我们调用compareFunc('age')生成比较函数后,排序便依据对象的age属性值进行。
XML节点的排序
4、XML节点的排序
尽管现代后端接口多返回轻量且易解析的JSON格式,但在某些旧项目中,数据仍以XML字符串形式返回。前端获取数据后需进行序列化,部分场景下还需排序。以往的做法是将XML转换为数组对象再排序,虽然可行但代码显得冗余繁琐。后来发现,XML解析后得到的也是类数组对象,将其转换为数组即可直接利用sort()进行排序。
// 1.模拟后端返回的XML字符串
var str=`
<root>
<user>
<name>tom</name>
<age>18</age>
</user>
<user>
<name>lucy</name>
<age>24</age>
</user>
<user>
<name>jhon</name>
<age>17</age>
</user>
<root>
`
// 2.定义比较函数
function compareFunction(prop){
return function (a, b) {
var value1= a.getElementsByTagName(prop)[0].textContent;
var value2= b.getElementsByTagName(prop)[0].textContent;
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else{
return 0;
}
}
}
// 3.xml字符串转换成xml对象
var domParser = new DOMParser();
var xmlDoc = domParser.parseFromString(str, 'text/xml');
var userElements=xmlDoc.getElementsByTagName('user'));
// 4.userElements类数组对象转换成数组再排序
var userElements=Array.prototype.slice.call(xmlDoc.getElementsByTagName('user'));
var _userElements=userElements.sort(compareFunction('age'));
// 5.打印排序后的结果
_userElements.forEach((user)=>{
console.log(user.innerHTML);
});
打印排序后的结果

结果显示,XML节点已按照age属性从小到大完成排序。
总结
5、总结
JavaScript数组的sort方法因支持传入比较函数而变得灵活多变,此外还可用于时间排序、汉字拼音首字母排序等场景。核心要点在于:通过传入比较函数明确两个对象属性值的比较逻辑,进而决定对象的排序顺序。本文总结了工作中遇到的典型问题及解决思路,如有不足,欢迎指正。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
