array.prototype.sort 默认按 utf-16 码点排序,导致中文等非 ascii 字符乱序;应使用 intl.collator("zh") 等语言敏感排序,兼容性好且支持拼音、假名、数值识别等功能。

sort 默认对中文、日文等非 ASCII 字符排序为什么乱序
因为 Array.prototype.sort 默认按字符串的 UTF-16 编码值逐字符比较,不是按语言习惯排序。比如 "苹果" 和 "香蕉" 在 JavaScript 中比较的是它们首字的 Unicode 码点("苹" 是 U+82F9,"香" 是 U+9999),但实际中文词典排序依赖拼音或笔画,UTF-16 顺序和拼音顺序几乎无关。
常见错误现象:["张三", "李四", "王五"].sort() 可能返回 ["李四", "王五", "张三"] —— 看似“有序”,实则纯属巧合,换一批字就错。
用 Intl.Collator 实现可靠的语言敏感排序
Intl.Collator 是目前最推荐的方式,它专为多语言排序设计,支持 locale、caseFirst、numeric 等选项,且浏览器兼容性良好(Chrome 24+/Firefox 29+/Safari 10+)。
- 中文默认按拼音排序:
new Intl.Collator("zh").compare(a, b) - 日文按假名顺序:
new Intl.Collator("ja").compare(a, b) - 忽略大小写 + 数值识别(如 "item2" 排在 "item10" 前):
new Intl.Collator("en", { numeric: true, caseFirst: "upper" })
实操示例:
const arr = ["苹果", "香蕉", "橙子"];
arr.sort(new Intl.Collator("zh").compare);
// → ["橙子", "苹果", "香蕉"](按拼音 chéng, píng, xiāng)
遇到 Safari 旧版本或 Node.js 早期版本时的降级方案
部分旧环境(如 Safari Intl.Collator 的某些选项,或完全缺失。此时不要 fallback 到手写拼音映射表(维护成本高、覆盖不全),而是优先检查是否支持基础构造:
- 先判断:
typeof Intl !== "undefined" && typeof Intl.Collator === "function" - 若不支持,可用
String.prototype.localeCompare作为轻量替代(它底层也调用 Collator,但 API 更简单):arr.sort((a, b) => a.localeCompare(b, "zh")) - 注意:
localeCompare在 Node.js 低版本中可能只支持 English locale,需配合 full-icu 启动(node --icu-data-dir=./node_modules/full-icu)
慎用自定义 compare 函数模拟拼音排序
网上常见“用 pinyin 库转拼音再 sort”的做法看似直观,但容易踩坑:
- 简繁混排时未统一转换(如 "后台" vs "後台"),
pinyin("後台")可能返回空或错误结果 - 多音字未处理(如 "重庆" 的“重”是 chóng 还是 zhòng?库通常只返回首读音)
- 性能差:每个元素调用一次拼音转换,O(n) 次额外字符串操作;而
Intl.Collator内部做了缓存与优化 - 引入第三方依赖增加打包体积,且 pinyin 库本身不保证 Unicode 最新版本支持
除非业务强要求「必须完全控制排序逻辑」(例如按方言读音或自定义权重),否则不要绕过 Intl.Collator。
真正难处理的是混合内容:一行含中、英、数字、emoji。这时候 locale 选 "zh" 或 "und"(未知语言)会影响 emoji 排序行为——"und" 更中立,但拼音排序能力弱。实际项目里建议按主语种定 locale,并接受小范围边界 case 的妥协。










