最近在写个人博客网站,遇到了一个数组嵌套对象排序的问题,在解决过程中遇到了一些坑。在此详细说一下,以免后来人踩坑!
需求描述
现有简化后的数据内容如下:
let data = [
{ArtId: 82, ArtName: "关于JavaScript处理时间戳转日期字符串与日期字符串转时间戳的函数", Date: 1630937933, State: 1,},
{ArtId: 83, ArtName: "在manjaro下安装安卓投屏软件scrcpy详细过程", Date: 1630937929, State: 1},
{ArtId: 84, ArtName: "学习GoFrame框架,从头开始一步步搭建个人博客WEB应用(中)", Date: 1630937925, State: 1},
{ArtId: 80, ArtName: "关于JavaScript存、取Cookie的函数", Date: 1630937921, State: 1}
]
现在需求是点击“标题”按钮,那么将data按ArtName升序排列,再点击一次倒序排列,再点一次还原到原来的顺序。 另外3个字段也是如此:点击“日期”按钮,按Date排序;点击“状态”按钮,按State排序;点击“ID”按钮,按“ArtId”排序。
分析需求
这里需要用到2个数组方法,一个是sort,一个是reverse。 使用方法相同,sort是升序排列,reverse是倒序排列。下面我重点讲一下sort: sort的调用方式是data.sort(function(key))。 这个funtion必须有一个参数,它必须是data数组中的键; 该函数会根据参数key提取sort函数传进来的2个元素的相关值:2个元素比较后返回正数那么做升序处理;返回0那么位置不变;返回负数那么做降序处理。 现在需要写一个可以同时比较数字、字符串以及异常情况的比较函数。
解决过程
首先写一个最简单的比较数字的函数,这个很简单,内容如下:
function compare(key) {
return function (a, b) {
let c = a[key]-b[key];
return c > 0 ? 1 : c === 0 ? 0 : -1;
}
}
这是一个闭包函数,key是数组中对象的键,a和b代表的是sort传进来的2个数组元素。
测试比较函数
这个简单,按f12打开控制台,把let data那段贴进去回车,然后把function compare贴进去回车,再执行data.sort(compare("Date")); 结果如下: 请注意,我执行了3次sort,每次结果都一致。 现在再来看看reverse,让我们执行3次data.reverse,看看是什么结果!
发现reverse的问题
是不是非常惊奇!!! sort方法对数组排序,同样的参数无论执行多少次结果都一致!! reverse方法对数组排序,同样的参数执行多次结果不一致!!! 请大家记住这个坑!!!太坑爹了,也没法看到reverse的源码,不知道为啥会这样,我们能做的就是不用reverse方法!
解决不能用reverse的问题
那么如何只用sort达到既可正向排序又可反向排序呢?? 请看下面的代码:
function compare(key,flag=1) {
flag = flag === 1 ? 1 : -1;
return function (a, b) {
let c = a[key]-b[key];
return flag*(c > 0 ? 1 : c === 0 ? 0 : -1);
}
}
加一个标志位参数,若没传第二个参数,那么是正向排序,如果传了第二个参数(无论第二个参数是啥)那么就逆向排序。 至于为啥写flag = flag === 1 ? 1 : -1; 这句代码,这是防止传参不合规。
最终解决方案
哎,写累了,麻溜贴最终代码,懂的自然懂,不懂的复制粘贴直接用吧!
function compare(key, flag = 1) {
flag = flag === 1 ? 1 : -1;
return function (a, b) {
if (typeof a[key] === "number" && typeof b[key] === "number") {
let c = a[key] - b[key];
return flag * (c > 0 ? 1 : c === 0 ? 0 : -1);
}
if (typeof a[key] === "undefined" || Number.isNaN(a[key])) {
if (typeof b[key] === "undefined" || Number.isNaN(b[key])) {
return 0;
} else {
return -flag;
}
}
if (typeof b[key] === "undefined" || Number.isNaN(b[key])) {
return flag;
}
a = a[key].toString();
b = b[key].toString();
return flag * (a > b ? 1 : a === b ? 0 : -1);
}
}
|