前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Intl.Collator 按语言规则比较字符串
JavaScript数据处理

中文名字用 sort() 排出来乱七八糟,怎么按拼音或语言习惯排序?

sort() 默认把元素转成字符串,按 UTF-16 编码一位一位比,所以中文不按拼音,item10 排在 item2 前面。面向用户的排序要用 new Intl.Collator(locale, options).compare 作比较函数,它按目标语言的规则比较,还能把数字片段按数值比较。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

排序规则来自语言,不来自编码

  1. locale决定用哪种语言的排序规则,同一个 ä 在德语和瑞典语里位置不同
  2. sensitivity决定大小写、重音符号算不算差别,搜索时常设成 base
  3. compare返回负数、0 或正数,直接交给 sort() 当比较函数

compare 只保证返回负数、0 或正数,不保证是 -1 或 1。写 collator.compare(a, b) === -1 这种判断,换个引擎可能就不成立了。

核心回答

先记住这个答案

Array.prototype.sort() 不传比较函数时,会把元素转成字符串,按 UTF-16 编码逐个字符比较。编码顺序和人的阅读习惯是两回事:中文的编码顺序不是拼音顺序,'item10' 因为第五个字符 '1' 小于 '2',排在了 'item2' 前面。按语言习惯排序要用 Intl.Collator:先 new Intl.Collator('zh-CN'),再把它的 compare 方法传给 sort()。需要数字按数值比较时加 numeric: true,想忽略大小写和重音时设置 sensitivity。

  • 默认 sort() 按 UTF-16 编码比较,不按字典顺序
  • Intl.Collator('zh-CN') 让中文按拼音排序
  • numeric: true 让 item2 排在 item10 前面
  • 大数组排序先建好 Collator 再复用

中文按拼音、编号按数值

后台管理页面最常见的两个排序需求:用户名按拼音排,文件名里的编号按数值大小排。默认的 sort() 两个都做不到。

默认排序和 Collator 对比JavaScript
const names = ['张三', '李四', '王五', '阿明']
console.log([...names].sort().join(' ')) // 按编码
console.log([...names].sort(new Intl.Collator('zh-CN').compare).join(' ')) // 按拼音

const files = ['item10', 'item2', 'Item1']
console.log([...files].sort().join(' ')) // 大写字母编码更小,排最前
const byNumber = new Intl.Collator('en', { numeric: true })
console.log([...files].sort(byNumber.compare).join(' '))
查看输出与解释
张三 李四 王五 阿明
阿明 李四 王五 张三
Item1 item10 item2
Item1 item2 item10

第一行碰巧和原数组顺序一样,只是因为这几个字的编码刚好是这个顺序,和拼音无关。用 zh-CN 的 Collator 之后,阿(a)、李(li)、王(wang)、张(zhang)按拼音排好了。 numeric: true 会把字符串里连续的数字当成一个整数来比,所以 2 排在 10 前面。文件名、版本号、订单编号这类混着数字的字符串,基本都需要这个选项。 compare 可以直接传给 sort(),因为 Collator 实例上的 compare 是已经绑定好的函数,不会丢 this。

同一对字符,换个语言结果就不同

Collator 的规则来自语言本身,不是一张全世界通用的表。另外,「两个字符串算不算相等」也可以调。

locale 和 sensitivity 的影响JavaScript
const letters = ['z', 'ä', 'a']
console.log(letters.sort(new Intl.Collator('de').compare).join(' ')) // 德语
console.log(letters.sort(new Intl.Collator('sv').compare).join(' ')) // 瑞典语

const base = new Intl.Collator('en', { sensitivity: 'base' })
console.log(base.compare('a', 'A'), base.compare('e', 'é')) // 大小写、重音都不算差别

const accent = new Intl.Collator('en', { sensitivity: 'accent' })
console.log(accent.compare('a', 'A'), accent.compare('e', 'é')) // 只有重音算差别
查看输出与解释
a ä z
a z ä
0 0
0 -1

德语把 ä 当成 a 的变体,排在 a 旁边;瑞典语里 ä 是一个独立字母,排在 z 后面。所以 locale 一定要按用户的语言传,别让它用运行环境的默认值。 sensitivity 有四档:base 只看基础字母,a、A、á 都算一样;accent 还看重音;case 还看大小写;variant 全都区分。做搜索框的模糊匹配时常用 base,用户输入 resume 也能匹配到 Résumé。

为什么要把 Collator 提到循环外面
每次 new Intl.Collator() 都要加载和解析语言数据,开销不小。在 sort() 的比较函数里写 a.localeCompare(b, 'zh-CN'),排一万条数据会触发几十万次比较,每次都可能重新准备一遍规则。先建一个 Collator,再复用它的 compare,是 MDN 也推荐的写法。
回答前,多想一步

容易答错的地方

以为 compare 一定返回 -1 或 1
规范只保证负数、0、正数。比较函数应该直接返回它的结果,判断先后时写 < 0,不要写 === -1。
不传 locale 还指望各端结果一致
不传时用运行环境的默认语言,服务端 Node 可能是 en-US,用户浏览器是 zh-CN,同一份数据排出两种顺序。分页列表在服务端排序、客户端又排一次,还会出现数据跳动。需要稳定结果就显式传语言。
用 sensitivity: 'base' 判断唯一性
base 下 'Admin' 和 'admin' 比较结果是 0。拿它做排序、搜索没问题,拿它判断用户名是否重复就会出问题。唯一性校验应该用明确的规范化规则,比如统一转小写再比较。
试着用自己的话回答

面试官还会怎么问?

localeCompare 和 Intl.Collator 怎么选?

a.localeCompare(b, locale, options) 的参数和 Collator 一样,结果也一样。偶尔比较一两次用 localeCompare 更顺手;排大数组、或者同一套选项要用很多次时,先建 Collator 再复用,性能更好。

多音字的拼音排序准吗?

不完全准。Collator 按字的常用读音排序,「重庆」的「重」可能按 zhòng 排。通讯录这类对拼音要求严格的场景,通常要借助拼音库先转出拼音,再按拼音字符串排序。

怎么让 A 和 a 排在一起,但大写排前面?

用 caseFirst: 'upper' 选项。默认情况下 Collator 已经把 A 和 a 排在一起,caseFirst 决定两者之间谁在前,可选 upper、lower 和 false。

从一道题,走向一组知识

把知识连起来

数据处理

「张三、李四和王五」这种列表文案,为什么不能直接用 join 拼?

排好序的名字要显示成「张三、李四和王五」,接着就要用 Intl.ListFormat 按语言习惯连起来。

数据处理

显示金额时,为什么不要写 '$' + amount,而要用 Intl.NumberFormat?

都是 Intl 家族的成员,一个管字符串按语言排序,一个管金额按地区格式化,用法都是先建实例再复用。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 中文按拼音、编号按数值
  3. 同一对字符,换个语言结果就不同
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑