之前做优惠券的时候有用到,而且一直对 sort 的顺序似是而非,所以做一个总结。
对以下数组进行排序,要求:价格低排前面、同价格邮费低在前、前两个相等销量高的在前。
const arr = [
{ name: '商品01', price: 123.0, sales: 123, postage: 19 },
{ name: '商品02', price: 124.0, sales: 123, postage: 0 },
{ name: '商品03', price: 123.0, sales: 133, postage: 29 },
{ name: '商品04', price: 125.0, sales: 123, postage: 9 },
{ name: '商品05', price: 123.0, sales: 143, postage: 19 }
];
复制代码
对 sort 函数简单记忆:返回结果大于 0,交换位置,否则不变。
利用 js 中 0 为 false 的特性,短路写法可以一行搞定:
arr.sort((a, b) => {
return a.price - b.price || a.postage - b.postage || b.sales - a.sales;
});
// arr:
[
{"name":"商品05","price":123,"sales":143,"postage":19},
{"name":"商品01","price":123,"sales":123,"postage":19},
{"name":"商品03","price":123,"sales":133,"postage":29},
{"name":"商品02","price":124,"sales":123,"postage":0},
{"name":"商品04","price":125,"sales":123,"postage":9}
]
复制代码
虽然这也不麻烦,但是能不能更方便一点?
实现一个对象数组多维排序函数:
const keys = ['price', 'postage', 'sales']; // 传入要排序的 key,优先级从高到低
const orders = [1, 1, -1]; // 每个 key 的排序方式,1 正序,-1 倒序
function multiSort(array, keys, orders) {
if (!keys) return array;
if (!orders) {
orders = Array.from({ length: keys.length }, () => 1); // 默认从小到大排序
}
return [...array].sort((a, b) => {
for (let [index, key] of keys.entries()) {
if (a[key] - b[key] === 0) continue; // 如果当前维度条件相等,判断下一个维度
return (a[key] - b[key]) * orders[index];
}
return 0; // 全部相等返回 0
});
}
const arr1 = multiSort(arr, keys, orders)
// arr1:
[
{"name":"商品05","price":123,"sales":143,"postage":19},
{"name":"商品01","price":123,"sales":123,"postage":19},
{"name":"商品03","price":123,"sales":133,"postage":29},
{"name":"商品02","price":124,"sales":123,"postage":0},
{"name":"商品04","price":125,"sales":123,"postage":9}
]
复制代码
其实前端能用到排序的机会并不多,一般列表都有分页,排序都是把条件传到后端。但是对于优惠券,或者其他数量一次性返回的列表进行排序,就需要自己上场了。
当然,这个函数是不严谨的:数组是浅拷贝,没有 keys 和 orders 长度不一致的防呆功能,没有参数类型验证。大型项目中这些都是要考虑的问题。