排序问题是比较常见的,最近的功能用到了前端的排序,当然其实大部分请求尤其是分页和配置的,都应该交给后端做排序,首先数组的排序用到了sort()函数
MDN对sort()的介绍
sort()
方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。
w3school对sort()的介绍
如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
- 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
- 若 a 等于 b,则返回 0。
- 若 a 大于 b,则返回一个大于 0 的值。
通过以上的信息,可以知道和map,forEach一样,sort函数接收一个回调函数作为参数,这个回调函数有两个形参,表示数组元素中的前者和后者,根据两者的差值做原地排序,废话不多说来一个最简单的demo体验一下
[1, 88, 12, 0, -10, 22].sort((a, b) => a - b)
等价于
[1, 88, 12, 0, -10, 22].sort(function(a, b){ return a - b})
当a大于b的时候,把a放到b的前面,对整个数组做迭代操作,大白话就是对整个数组做升序排列
[-10, 0, 1, 12, 22, 88]
当然实际的开发中的数据肯定复杂得多,模拟一个需求对数组[ '标签名', '通配符', '内联', 'id', '类名' ]进行排序,对于前端来说很熟了,权重是 内联 < id < 类名 < 标签名 < 通配符,按照字符串排序肯定是行不通的,我们要把权重的排序规则具象化,最直观的方法,通过js的键值形式重新生成一套数组让每一个元素变成{value: '标签名',weight: 400 },最后对每一个元素的weight比较就行了
const rules = [
{value: '类名', weight: 300},
{value: '内联', weight: 100},
{value: 'id', weight: 200},
{value: '标签名', weight: 400},
{value: '通配符', weight: 500}
]
有了规则就好办了,每一次拿到值的时候都去rules里面去查它的权重是多少然后比较就行了
const array = [ '标签名', '通配符', '内联', 'id', '类名' ]
array.sort((a,b)=>{
//使用数组的find函数找到a,b的权重,
const aw = rules.find(obj => obj.value == a).weight;
const bw = rules.find(obj => obj.value == b).weight;
return aw - bw;
})
如果考虑配置不全的情况,同样是升序排列
array.sort((a,b)=>{
const av = rules.find(obj => obj.value == a);
const bv = rules.find(obj => obj.value == b);
//如果没找到就给一个默认值
let aw = 9999;
let bw = 9999;
if(av){ aw = av.weight; }
if(bv){ bw = bv.weight; }
return aw - bw;
})
有没有优化的方法呢,一提到排序我想到了数字也就是自然序列,排序的配置我可以不使用键值对象,直接用排好的数组,然后对比下标值
const rules = ['地月系', '太阳系', '银河系', '本星系群', '室女座超星系团', '宇宙视界'];
const array = [ '地月系', '本星系群', '太阳系', '银河系', '宇宙视界', '室女座超星系团'];
array.sort((a,b)=>{
//使用indexOf函数找到a,b的下标
const ai = rules.indexOf(a);
const bi = rules.indexOf(b);
return ai - bi;
})
注意indexOf如果找不到元素会返回-1,这个默认值也需要处理成我们想要的值,重点在于排序规则的配置和空值的处理,只要理解了这个,代码的实现层面还是比较简单的,多练习一下