JavaScript如何最优实现对象数组双属性优先级排序
JavaScript 实现类MySQL ORDER BY逻辑的多字段数组排序
问题场景
现有如下结构的对象数组:
const names = [ {firstName: "Rachel", lastName: "Green"}, {firstName: "Monica", lastName: "Geller"}, {firstName: "Ross", lastName: "Geller"}, {firstName: "Phoebe", lastName: "Buffay"} ]
需求为:对该数组先按firstName属性排序,若存在firstName取值相同的元素,则对这部分同值元素再按lastName属性排序,排序效果和MySQL中ORDER BY关键字的多字段排序逻辑完全一致,如何用JavaScript以最优性能实现?
最优实现方案
直接使用JavaScript数组原生的sort()方法自定义比较函数即可,原生sort由JS引擎底层做了性能优化,是性能最好的实现方式,不需要引入任何第三方依赖。
针对当前场景的直接实现
names.sort((a, b) => { // 优先比较firstName if (a.firstName !== b.firstName) { return a.firstName.localeCompare(b.firstName) } // firstName相等时再比较lastName return a.lastName.localeCompare(b.lastName) })
逻辑说明
- 排序规则和MySQL
ORDER BY firstName, lastName的默认升序逻辑完全对齐:高优先级字段优先比较,仅当高优字段值相等时,才会比较下一优先级的字段 - 字符串比较优先用
localeCompare(),不要直接用>/<做比较:前者符合自然语言排序规则,能正确处理非英文字符、带重音符号的字符场景,和MySQL默认字符串排序行为一致 - 如果需要对字段做降序排序,只需要把对应字段的比较结果取反即可,例如
return -a.firstName.localeCompare(b.firstName)就是firstName字段降序 - 如果排序字段是数字类型,直接返回
a[字段名] - b[字段名]即可,不需要调用localeCompare()
通用多字段排序封装
如果业务中经常需要做多字段排序,可以封装一个通用的比较函数生成器,支持自定义排序字段、每个字段的排序方向,避免重复写比较逻辑:
/** * 生成多字段排序比较函数 * @param {Array<{key: string, order?: 'asc'|'desc'}>} sortRules 排序规则,数组顺序即为字段优先级从高到低 * @returns 可直接传入Array.sort的比较函数 */ function createSorter(sortRules) { return (a, b) => { for (const rule of sortRules) { const { key, order = 'asc' } = rule const valA = a[key] const valB = b[key] if (valA === valB) continue // 自动区分字符串、数字类型的比较逻辑 let compareResult = typeof valA === 'string' ? valA.localeCompare(valB) : valA - valB return order === 'desc' ? -compareResult : compareResult } return 0 } } // 使用示例:先按firstName升序,再按lastName升序 names.sort(createSorter([ { key: 'firstName' }, { key: 'lastName' } ]))
内容的提问来源于stack exchange,提问作者Sejal Naik
相关产品推荐
相关产品推荐

