JavaScript数组sort方法详解:从默认排序到自定义排序

作者:小括号

时间:2026-10-24

浏览:371

本文详细介绍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);
});

打印排序后的结果

JavaScript数组sort方法详解:从默认排序到自定义排序

结果显示,XML节点已按照age属性从小到大完成排序。

总结

5、总结

JavaScript数组的sort方法因支持传入比较函数而变得灵活多变,此外还可用于时间排序、汉字拼音首字母排序等场景。核心要点在于:通过传入比较函数明确两个对象属性值的比较逻辑,进而决定对象的排序顺序。本文总结了工作中遇到的典型问题及解决思路,如有不足,欢迎指正。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章