JavaScript sort()默认按Unicode排序,数字排序需显式转换防NaN,对象排序应单函数多级比较,比较函数须为纯函数,国际化排序用localeCompare()。

JavaScript 中 sort() 方法默认按字符串 Unicode 码点排序,直接用于数字或复杂对象时极易出错。要实现真正高性能、可预测的排序,关键不在算法本身(V8 引擎已用 TimSort 优化),而在于写对比较函数——它决定了排序逻辑是否正确、稳定,以及能否被引擎高效执行。
数字排序:别再用 a - b 的“捷径”
虽然 [3, 10, 2].sort((a, b) => a - b) 看似简洁,但存在隐式类型转换风险:若数组含 null、undefined 或字符串数字(如 "5"),a - b 会返回 NaN,导致整个排序结果不可控(部分浏览器中数组可能被清空或乱序)。
更稳妥的做法是显式转换并校验:
- 先用
Number()或一元加号+a转换,再比较 - 对非数值项返回固定顺序(如排在末尾),避免
NaN
示例:
arr.sort((a, b) => {const na = +a, nb = +b;
if (isNaN(na)) return 1;
if (isNaN(nb)) return -1;
return na - nb;
});
对象排序:按多字段分级,兼顾可读与性能
对对象数组按多个属性排序(如先按 status 升序,再按 createdAt 降序),不要嵌套 if-else 或多次调用 sort()(性能差且不稳定)。应在一个比较函数中完成分级判断:
- 逐级比较:当前字段相等才进入下一级
- 用三元运算符或短路逻辑返回结果,减少分支
- 日期字段优先转为时间戳再比较,避免字符串比对误差
示例(按状态升序、创建时间降序):
items.sort((a, b) => {const statusDiff = a.status.localeCompare(b.status);
if (statusDiff !== 0) return statusDiff;
return new Date(b.createdAt) - new Date(a.createdAt);
});
稳定性与性能:避免副作用,保持纯函数
sort() 是原地排序,但比较函数必须是纯函数——不能修改参数、不依赖外部变量、不产生副作用。否则可能引发以下问题:
- 引擎无法安全优化(如内联或缓存比较结果)
- 在不同 V8 版本或浏览器中行为不一致
- 并发调用时出现竞态(尤其在 Web Worker 中)
常见反模式:
- 在比较函数里调用
console.log或发送网络请求 - 修改
a或b的属性(如a.rank++) - 依赖闭包中的可变状态(如计数器)
特殊需求:自定义规则与国际化支持
当需要忽略大小写、处理中文拼音、或按本地化规则排序时,别手动实现字符串比较逻辑。应使用标准 API:
- 英文/通用文本:用
String.prototype.localeCompare(),传入{ sensitivity: 'base' }忽略大小写 - 中文排序:同样用
localeCompare(),指定locale: 'zh-CN',现代浏览器会按拼音排序 - 需稳定排序且要求严格顺序时,可在比较前添加索引字段,作为最终判据
示例(中文名称升序,忽略大小写):
list.sort((a, b) => a.name.localeCompare(b.name, 'zh-CN', {sensitivity: 'base'
}));


















