HOWTO · JavaScript

在 JavaScript 中按属性对对象数组进行排序

本教程演示了如何按某些属性对对象数组进行排序。

本页内容

要按对象的某个属性对对象数组排序,请向 sort() 传入比较函数。比较函数会读取两个对象的该属性:第一个对象应排在前面时返回负数,应排在后面时返回正数,键值相同时返回零。字符串键使用字符串比较,数值键则使用减法。

按字符串属性对对象数组排序

比较前,可以先对两个字符串进行规范化。这样,示例会忽略大小写进行排序,同时保留对象中每个原始的 lastName 值。

运行此示例:

本节中的代码以及显示的标签或输出仍为英文。

const students = [
  { firstName: 'Rohan', lastName: 'Dalal', age: 19 },
  { firstName: 'Zain', lastName: 'Ahmed', age: 17 },
  { firstName: 'Anadi', lastName: 'Malhotra', age: 19 }
];

students.sort((a, b) => {
  const left = a.lastName.toLowerCase();
  const right = b.lastName.toLowerCase();
  if (left < right) return -1;
  if (left > right) return 1;
  return 0;
});

console.log(students.map(student => student.lastName).join(', '));
Ahmed, Dalal, Malhotra

比较函数返回的是 sort() 所需的排序信号,不必恰好返回 -1 或 1;返回负数、零或正数即可。如果不希望大小写影响顺序,可以先将字符串转换为小写。toLowerCase() 会返回一个新字符串,因此不会修改对象中保存的姓名。

使用 localeCompare() 比较字符串

对于字符串属性,localeCompare() 能简洁地构造比较函数,并按照语言相关的排序规则进行比较。它返回负数、零或正数,因此可以直接用于 sort():

本节中的代码以及显示的标签或输出仍为英文。

const students = [
  { firstName: 'Rohan', lastName: 'Dalal', age: 19 },
  { firstName: 'Zain', lastName: 'Ahmed', age: 21 },
  { firstName: 'Anadi', lastName: 'Malhotra', age: 16 }
];

students.sort((a, b) => a.lastName.localeCompare(b.lastName));
console.log(students.map(student => student.lastName).join(', '));
Ahmed, Dalal, Malhotra

当键是文本,且适合采用符合语言习惯的比较方式时,可以选择此方法。localeCompare() 比较的是字符串,不能用于数值排序。如果要明确指定语言,或设置区分大小写等选项,可以将运行环境支持的语言和选项传给 localeCompare()。

按数值属性排序

用第一个对象的数值键减去第二个对象的数值键。如果第一个对象的年龄较小,a.age - b.age 就是负数,因此升序排列时 a 会排在 b 前面。

本节中的代码以及显示的标签或输出仍为英文。

const students = [
  { firstName: 'Rohan', lastName: 'Dalal', age: 19 },
  { firstName: 'Zain', lastName: 'Ahmed', age: 21 },
  { firstName: 'Anadi', lastName: 'Malhotra', age: 16 }
];

students.sort((a, b) => a.age - b.age);
console.log(students.map(student => student.age).join(', '));
16, 19, 21

这种减法方式适用于数值。不要用它比较姓名:字符串相减无法表示字母顺序。同样,不传入比较函数也不会让 sort() 自动检查对象属性;默认排序会比较数组元素转换成的字符串表示,因此对象通常需要显式传入比较函数。

按降序排序

交换比较函数的两个操作数即可反转排序方向。对于年龄数值,使用 b.age - a.age 会让年龄较大的对象排在前面。这样,排序规则始终针对选定的属性,也不必先按一个方向排序,再反转整个数组。

本节中的代码以及显示的标签或输出仍为英文。

const students = [
  { firstName: 'Rohan', lastName: 'Dalal', age: 19 },
  { firstName: 'Zain', lastName: 'Ahmed', age: 21 },
  { firstName: 'Anadi', lastName: 'Malhotra', age: 16 }
];

students.sort((a, b) => b.age - a.age);
console.log(students.map(student => student.age).join(', '));
21, 19, 16

若要按字符串降序排列,可以反转字符串比较函数的结果,例如对 a.lastName.localeCompare(b.lastName) 取负值。比较函数应保持一致,使键值相等时仍返回零。

sort() 的重要行为与限制

sort() 会就地修改数组,并返回同一个数组。如果还需要保留原始顺序,请先用 const sortedStudents = [...students] 复制数组,再对副本排序。对象本身不会被克隆;排序改变的是它们在数组中的位置,而不是对象属性。

如果不传入比较函数,sort() 会将值转换为字符串并比较这些字符串。因此,默认排序不适用于数值排序,也不会按对象的某个属性排序。请提供与键类型相符的比较函数。这些示例假定每个对象都有指定的字符串或数值属性;它们没有规定如何处理缺失的键或混合类型。遇到这类数据时,请先验证数据,或确定这些值应如何参与比较。

有关数组 API 的详细信息,请参阅 sort() 方法参考。