引入
说明:使用语言为js。
对象数组,即数组中存放的元素是一个个对象。例如
let objArr = [
{ name: "张三", sex: 'female', age: 30, birthday: "1994/10/11" },
{ name: "李四", sex: 'male', age: 20, birthday: "2001/08/11" },
{ name: "王五", sex: 'female', age: 40, birthday: "2001/01/15" }
];
但是我们可能需要对该对数组中对象的指定属性进行排序,例如上述对象数组中的age,birthday。如何操作?方法之一,就是数组的sort()方法。
下面,就一步步去分析,实现一份简单通用的对象数组排序方法。
实现对象数组排序
第一步:简单排序number属性
因为Array.sort()的“默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的”。好在是sort()方法接受一个用来指定按某种顺序进行排列的函数作为可选参数,即arr.sort([compareFunction])
,如果 compareFunction(a, b) 小于0,那么a会被排列到b之前;所以可以在此实现自己想要的排序方法。
注意,sort方法会改变原数组。(sort() 方法用原地算法对数组的元素进行排序,并返回数组。)
话不多说,直接看。
例如上述objArr,按照age升序排序:
// 指定排序的比较函数
function compare(property) {
return function (object1, object2) {
let value1 = object1[property];
let value2 = object2[property];
// 升序
return value1 - value2;
}
}
let sortObj = objArr.sort(compare("age"));
console.log(sortObj);
应该会得到如下结果:
第二阶段:可以排序string属性
但是这个写法只能对age这个number类型的属性其作用,如果换成name或者birthday等,就不行,因为string不能直接用'-'比较得出大小。
例如,运行console.log('male' - 'female');
,应该会看到得出的是NaN。
string,就应该使用localeCompare() 方法,它返回一个数字来指示一个参考字符串是否在排序顺序前面或之后或与给定字符串相同。完整语法:referenceStr.localeCompare(compareString[, locales[, options]])
。
所以需要简单修改一下compare()方法,修改如下:
function compare(property) {
return function (object1, object2) {
let value1 = object1[property];
let value2 = object2[property];
if (typeof (value1) == typeof (value2)) {
if (typeof (value1) === 'number') {
return value1 - value2;
}
if (typeof (value1) === 'string') {
// 升序
return value1.toString().localeCompare(value2);
}
}
}
}
let sortObj = objArr.sort(compare("birthday"));
console.log(sortObj);
结果应当如下:
第三阶段:可以指定升序/降序
既然已经到了这个程度,那可以再加一个是按照升序或者降序排列。
简单修改如下:
function compare(property, sortType = "asc") {
return function (object1, object2) {
let value1 = object1[property];
let value2 = object2[property];
// 判断 传入的属性值 是number还是 string
if (typeof (value1) == typeof (value2)) {
if (typeof (value1) === 'number') {
// 如果是升序
if (sortType === "asc") {
return value1 - value2;
} else if (sortType === "desc") {
// 如果是降序
return value2 - value1;
}
}
if (typeof (value1) === 'string') {
// 如果是升序
if (sortType === "asc") {
return value1.toString().localeCompare(value2);
} else if (sortType === "desc") {
// 如果是降序
return value2.toString().localeCompare(value1);
}
}
}
}
}
// 生日,降序
let sortObj = objArr.sort(compare("birthday", 'desc'));
console.log(sortObj);
得到的结果应该如下:
第四阶段:封裝成通用方法
反正都这样了,再简单封装一下,导出成一个方法,后续直接使用。
新建一个objArraySort.js,放入以下代码:
// sort使用的排序方法
// 传入对象数组用于排序的对象的属性,升序/降序
function compare(property, sortType = "asc") {
// 如果不是 asc,desc,不做下一步比较
if (!(sortType === "desc" || sortType === "asc")) {
return;
}
return function (object1, object2) {
// 取得对象属性值
let value1 = object1[property];
let value2 = object2[property];
// 如果该对象不存在这个属性,也不做后续比较
if (!value1 || !value2) {
return;
}
// 如果两个属性取得的值不是一个类型的就不用比较了
if (typeof (value1) == typeof (value2)) {
// 判断 传入的属性值 是number还是 string
if (typeof (value1) === 'number') {
// 如果是升序
if (sortType === "asc") {
return value1 - value2;
} else {
// 如果是降序
return value2 - value1;
}
} else if (typeof (value1) === 'string') {
// 如果是升序
if (sortType === "asc") {
return value1.toString().localeCompare(value2);
} else {
// 如果是降序
return value2.toString().localeCompare(value1);
}
} else {
// 其它类型就不排序了
return;
}
} else {
return;
}
}
}
// 通用方法,需要传入 需要排序的对象数组、对象属性、排序方式
function objectArraySort(array, property, sortType) {
// 如果不是对象数组用这个方法,返回的是undefined
if (!(array instanceof Array)) {
return;
}
return array.sort(compare(property, sortType));
}
// 导出
module.exports = {
objectArraySort: objectArraySort,
}
再将刚刚的objArr按照age降序排序:
// 引入模块
const oas = require("./objectArraySort");
// 调用方法,传入需要排序的对象数组、对象属性、排序方式
let sortObj = oas.objectArraySort(objArr, 'age', 'desc');
console.log(sortObj);
应该会得到以下结果:
至此,一个简单通用的对象数组按照其对象指定属性排序的模块就完成了。实践有效,如果有问题,可提出交流,谢谢。