在处理 JavaScript 对象数组时,特别是当对象有复杂嵌套结构时,对数组进行排序可能会变得复杂。本文将介绍一种通用的方法来根据对象属性值对对象数组进行排序,包括处理嵌套对象的情形。
解决方案总结
本文提供的方法是基于 @ege-Özcan 在 StackOverflow 上的回答。我们将通过编写一个通用的函数 dynamicMultiSort
来实现对象数组的多级排序。
问题描述
假设我们有以下数据结构 People
:
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename: "Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
我们的目标是首先根据 People.Name.name
排序,然后根据 People.Name.surname
进行次级排序。
挑战
我们希望实现动态属性访问,如果直接使用对象访问器 People['Name.name']
是无效的,People['Name']['name']
则是静态方法,我们希望的是更具动态性的解决方案。
解决方案详解
通过递归访问对象的属性,我们可以实现对嵌套对象的排序。下面是完整的代码实现及步骤讲解。
数据准备
首先,我们定义好需要排序的对象数组:
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename: "Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
多级排序函数
我们将实现 dynamicMultiSort
函数,该函数用于多级排序:
function dynamicMultiSort() {
var args = Array.prototype.slice.call(arguments);
return function (a, b) {
var i = 0, result = 0, numberOfProperties = args.length;
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(args[i])(a, b);
i++;
}
return result;
}
}
动态排序函数
利用 dynamicSort
实现针对单个属性的排序,该函数还负责确定排序顺序(升序或降序):
function dynamicSort(properties) {
var sortOrder = 1;
if(properties[properties.length - 1][0] === "-") {
sortOrder = -1;
properties[properties.length - 1] = properties[properties.length - 1].substr(1);
}
return function (a,b) {
var propertyOfA = recurseObjProp(a, properties)
var propertyOfB = recurseObjProp(b, properties)
var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
return result * sortOrder;
};
}
递归属性访问函数
实现 recurseObjProp
函数,用于递归访问对象属性,直到访问到目标叶子节点:
function recurseObjProp(root, leafs, index) {
index = index || 0;
var upper = root;
var lower = upper[leafs[index]];
if (!lower) {
return upper;
}
index++;
return recurseObjProp(lower, leafs, index);
}
实现全部代码
结合上述方法,下面是完整的代码实现:
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
People.sort(dynamicMultiSort(['Name', 'name'], ['Name', '-surname']));
console.log(People);
function dynamicMultiSort() {
var args = Array.prototype.slice.call(arguments);
return function (a, b) {
var i = 0, result = 0, numberOfProperties = args.length;
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(args[i])(a, b);
i++;
}
return result;
}
}
function dynamicSort(properties) {
var sortOrder = 1;
if(properties[properties.length - 1][0] === "-") {
sortOrder = -1;
properties[properties.length - 1] = properties[properties.length - 1].substr(1);
}
return function (a,b) {
var propertyOfA = recurseObjProp(a, properties);
var propertyOfB = recurseObjProp(b, properties);
var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
return result * sortOrder;
};
}
function recurseObjProp(root, leafs, index) {
index = index || 0;
var upper = root;
var lower = upper[leafs[index]];
if (!lower) {
return upper;
}
index++;
return recurseObjProp(lower, leafs, index);
}
结果验证
执行该代码后,People
数组将会被正确排序:
[
{ Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
{ Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' },
{ Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' }
]
可以看到,数组首先按照 Name.name
排序,再次级按 Name.surname
排序。
总结
本文介绍了如何在 JavaScript 中根据对象的嵌套属性对对象数组进行排序。通过实现通用的 dynamicMultiSort
函数,我们可以实现具有高度灵活性的排序功能,无需引入第三方库。对复杂数据结构进行排序是许多开发场景中常见的需求,掌握这种通用解决方案可以提高代码的复用性和可维护性。