码云笔记前端博客
Home > 前端技术 > Tip:如何在JavaScript中对对象数组排序

Tip:如何在JavaScript中对对象数组排序

2018-11-28 分类:前端技术 作者:码云 阅读(429)

本文共计5658个字,预计阅读时长需要15分钟。

如果你有一个对象数组,需要按一定顺序排序,那么你可能会倾向于使用JavaScript库。但是,在你这样做之前,请记住,您可以使用本地的数组排序函数进行一些非常整洁的排序。

在本文中,我将向您展示如何在JavaScript中对对象数组进行排序,而不会引起任何麻烦。

要阅读本文,你需要了解基本的JavaScript概念,例如声明变量、编写函数和条件语句。我还将使用ES6语法。

Tip:如何在JavaScript中对对象数组排序

基本数组排序

默认情况下是JavaScript 的Array.sort函数将数组中要排序的每个元素转换为字符串,并按Unicode代码点顺序对它们进行比较

1
2
3
4
5
const foo = [8, 3, 5, 'whistle', 'fish'];
foo.sort(); // 返回 [3, 5, 8, 'fish', 'whistle']

const bar = [4, 19, 30, function(){}, {key: 'value'}];
bar.sort(); // 返回 [ 19, 30, 4, { key: 'value' }, [Function] ]

你可能想知道为什么30在4点之前。不合乎逻辑的,嗯?事实上是这样的。这是因为数组中的每个元素首先被转换为字符串,并且按照Unicode顺序,所以“30”在“4”之前。

值得注意的是,与许多其他JavaScript数组函数不同,Array.sort实际上会改变或改变它所排序的数组。

1
2
3
const baz = ['hello world', 31, 5, 9, 12];
baz.sort(); // baz数组被修改
console.log(baz); // 展示 [12, 31, 5, 9, "hello world"]

为了避免这种情况,可以创建要排序的数组的新实例,并修改它。

1
2
3
4
const baz = ['hello world', 31, 5, 9, 12];
const newBaz = [...baz].sort(); // 创建并排序baz数组的新实例
console.log(baz); // "hello world", 31, 5, 9, 12]
console.log(newBaz); // [12, 31, 5, 9, "hello world"]

注意,spread操作符用于创建baz的新实例。

大家可以试试以下代码:

1
2
3
4
5
const baz = ['hello world', 31, 5, 9, 12];
const newBaz = baz.slice().sort();

console.log(baz);
console.log(newBaz);

运行结果:

1
2
["hello world", 31, 5, 9, 12]
[12, 31, 5, 9, "hello world"]

使用Array.sort单独排序对于对象数组的排序不是很有用。值得庆幸的是,该函数接受一个可选的compareFunction参数,该参数将根据compare函数的返回值对数组元素进行排序。

使用比较函数排序

假设a和b是被比较函数比较的两个元素。如果比较函数的返回值为:

  • 小于0 - a在b之前
  • 大于0 - b在a之前
  • 等于0 - a和b保持不变

让我们看一个简单的数字数组例子:

1
2
3
4
5
6
7
8
9
10
11
const arr = [1, 2, 30, 4];

function compare(a, b){
if (a > b) return 1;
if (b > a) return -1;

return 0;
}

arr.sort(compare);
// 1, 2, 4, 30

这个可以被重构,通过从b中减去a得到返回值:

1
2
3
function compare(a, b){
return a - b;
}

这是一个很好的箭头函数:

1
arr.sort((a, b) => a - b);

如果您不熟悉箭头函数,可以在这里阅读更多关于它们的信息:ES6箭头函数:JavaScript中丰富而简洁的语法

在JavaScript中对对象数组进行排序

现在让我们看看对象数组的排序。让我们拿一个带对象数组:

1
2
3
4
5
const bands = [
{ genre: 'Rap', band: 'Migos', albums: 2},
{ genre: 'Pop', band: 'Coldplay', albums: 4},
{ genre: 'Rock', band: 'Breaking Benjamins', albums: 1}
];

我们可以使用下面的比较函数对这个对象数组按照类型进行排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function compare(a, b) {
// 使用toUpperCase()忽略字符大小写
const genreA = a.genre.toUpperCase();
const genreB = b.genre.toUpperCase();

let comparison = 0;
if (genreA > genreB) {
comparison = 1;
} else if (genreA < genreB) {
comparison = -1;
}
return comparison;
}

bands.sort(compare);

/* returns [
{ genre: 'Pop', band: 'Coldplay', albums: 4 },
{ genre: 'Rap', band: 'Migos', albums: 2 },
{ genre: 'Rock', band: 'Breaking Benjamins', albums: 1 }
] */

逆排序顺序,你可以简单地转化比较函数的返回值:

1
2
3
4
5
6
function compare(a, b) {
...

//将返回值乘以 -1
return comparison * -1;
}

大家可以试一下下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const bands = [
{ genre: 'Rap', band: 'Migos', albums: 2},
{ genre: 'Pop', band: 'Coldplay', albums: 4},
{ genre: 'Rock', band: 'Breaking Benjamins',
albums: 1}
];

function compare(a, b) {
const genreA = a.genre.toUpperCase();
const genreB = b.genre.toUpperCase();

let comparison = 0;
if (genreA > genreB) {
comparison = 1;
} else if (genreA < genreB) {
comparison = -1;
}
return comparison;
}

console.log(bands.sort(compare));

运行结果展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
[[object Object] {
albums: 4,
band: "Coldplay",
genre: "Pop"
}, [object Object] {
albums: 2,
band: "Migos",
genre: "Rap"
}, [object Object] {
albums: 1,
band: "Breaking Benjamins",
genre: "Rock"
}]

创建一个动态排序函数

让我们创建一个排序函数,您可以使用它对数组对象进行排序,这些对象的值要么是字符串,要么是数字。这个函数有两个参数——我们想要排序的键和结果的排序(即升序或降序)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const bands = [
{ genre: 'Rap', band: 'Migos', albums: 2},
{ genre: 'Pop', band: 'Coldplay', albums: 4, awards: 13},
{ genre: 'Rock', band: 'Breaking Benjamins', albums: 1}
];

// 动态排序函数
function compareValues(key, order='asc') {
return function(a, b) {
if(!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
// 属性在这两个对象上都不存在
return 0;
}

const varA = (typeof a[key] === 'string') ?
a[key].toUpperCase() : a[key];
const varB = (typeof b[key] === 'string') ?
b[key].toUpperCase() : b[key];

let comparison = 0;
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
return (
(order == 'desc') ? (comparison * -1) : comparison
);
};
}

你可以这样使用它:

1
2
3
4
5
6
7
8
// array is sorted by band, in ascending order by default
bands.sort(compareValues('band'));

// array is sorted by band in descending order
bands.sort(compareValues('band', 'desc'));

// array is sorted by albums in ascending order
bands.sort(compareValues('albums'));

举例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const bands = [
{ genre: 'Rap', band: 'Migos', albums: 2},
{ genre: 'Pop', band: 'Coldplay', albums: 4},
{ genre: 'Rock', band: 'Breaking Benjamins',
albums: 1}
];

function compareValues(key, order='asc') {
return function(a, b) {
if(!a.hasOwnProperty(key) ||
!b.hasOwnProperty(key)) {
return 0;
}

const varA = (typeof a[key] === 'string') ?
a[key].toUpperCase() : a[key];
const varB = (typeof b[key] === 'string') ?
b[key].toUpperCase() : b[key];

let comparison = 0;
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
return (
(order == 'desc') ?
(comparison * -1) : comparison
);
};
}

console.log(
bands.sort(compareValues('band', 'desc'))
);

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
[[object Object] {
albums: 2,
band: "Migos",
genre: "Rap"
}, [object Object] {
albums: 4,
band: "Coldplay",
genre: "Pop"
}, [object Object] {
albums: 1,
band: "Breaking Benjamins",
genre: "Rock"
}]

在上面的代码中,hasOwnProperty方法用于检查指定的属性是否在每个对象上定义,并且没有通过原型链继承。如果没有在对象上定义它,函数返回0,这将导致排序顺序保持不变。

类型运算符还用于检查属性值的数据类型。这允许函数确定正确的数组排序方法。例如,如果指定属性的值是字符串,则使用toUpperCase方法将其所有字符转换为大写,因此在排序时忽略字符大小写。

你可以调整上述函数以适应其他数据类型和脚本需要的任何其他特性。

String.prototype.localeCompare()

在上面的示例中,我们希望能够对对象数组进行排序,这些对象的值要么是字符串,要么是数字。但是,如果您知道您将只处理值为字符串的对象,那么您可以使用JavaScript的localeCompare方法稍微整理一下代码。

此方法返回一个数字,该数字指示字符串在排序顺序上是否与给定字符串相同。它支持不区分大小写的数组:

1
2
3
4
5
["motorhead", "Motorhead", "Mötorhead"].sort();
// ["Motorhead", "Mötorhead", "motorhead"]

["motorhead", "Motorhead", "Mötorhead"].sort((a, b) => a.localeCompare(b));
// ["motorhead", "Motorhead", "Mötorhead"]

compareValues函数而言,这意味着我们可以写:

1
2
3
4
5
6
7
8
9
10
function compareValues(key, order='asc') {
return function(a, b) {
if(!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) return 0;
let comparison = a[key].localeCompare(b[key]);

return (
(order == 'desc') ? (comparison * -1) : comparison
);
};
}

结论

这就是对数组对象排序的简短介绍。尽管许多JavaScript库提供了这种动态排序能力(例如Underscore.js,Lodash 和 Sugar)。正如所演示的那样,自己实现这种功能并不困难。

如果你有任何问题或意见,请随意在下面留言。

「除特别注明外,本站所有文章均为码云笔记原创,转载请保留出处!」

赞(2) 打赏

觉得文章有用就打赏一下文章作者

支付宝
微信
2

觉得文章有用就打赏一下文章作者

支付宝
微信

上一篇:

下一篇:

你可能感兴趣

共有 2 条评论 - Tip:如何在JavaScript中对对象数组排序

  1. 天桥下的等待 Linux Chrome 62.0.3202.84

    数组排序

    1. 码云 Windows 7 Chrome 63.0.3239.132

      @天桥下的等待有什么问题可以留言探讨

博客简介

码云笔记 mybj123.com,一个专注Web前端开发技术的博客,主要记录和总结博主在前端开发工作中常用的实战技能及前端资源分享,分享各种科普知识和实用优秀的代码,以及分享些热门的互联网资讯和福利!码云笔记有你更精彩!
更多博客详情请看关于博客

精彩评论

站点统计

  • 文章总数: 456 篇
  • 分类数目: 13 个
  • 独立页面: 8 个
  • 评论总数: 215 条
  • 链接总数: 15 个
  • 标签总数: 1009 个
  • 建站时间: 494 天
  • 访问总量: 8652499 次
  • 最近更新: 2019年10月21日