前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库数组 sort 默认字符串 Unicode 排序
JavaScript数组与集合

数字数组直接 sort 为什么会把 10 排在 9 前面?

sort() 不传比较函数时,会先把元素转成字符串,再按字符编码逐位比较。"10" 的第一位是 "1",比 "9" 小,所以 10 排在 9 前面。按数字排序要传 (a, b) => a - b。

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

比较器的返回值决定谁在前

  1. 返回负数a 排在 b 前面
  2. 返回正数b 排在 a 前面
  3. 返回 0两者相等,保持原来的先后顺序

默认排序比较的是 UTF-16 编码,不是按人的阅读习惯排。中文姓名、带数字的文件名要用 localeCompare 或 Intl.Collator。

核心回答

先记住这个答案

sort() 不传比较函数时,会把每个元素转成字符串,再按 UTF-16 编码一位一位地比。10 变成 "10",9 变成 "9",比第一位时 "1" 小于 "9",所以 10 排到了前面。要按数值排序就传比较函数:升序写 (a, b) => a - b,降序写 (a, b) => b - a。比较函数返回负数表示 a 在前,正数表示 b 在前,0 表示相等。

  • 默认排序按字符串逐位比较,不按数值大小
  • 数字升序写 (a, b) => a - b
  • 比较器看返回值正负,返回布尔值是错的
  • sort() 会改原数组,undefined 永远排最后

同一组数字,两种排法

先看默认排序和数值排序放在一起的结果。

默认排序和数值比较器对比JavaScript
const values = [10, 9, 20, 2]

console.log(JSON.stringify([...values].sort()))               // 按字符串比
console.log(JSON.stringify([...values].sort((a, b) => a - b))) // 按数值比
console.log(JSON.stringify(values))                            // 原数组没动,因为排的是副本
查看输出与解释
[10,2,20,9]
[2,9,10,20]
[10,9,20,2]

默认排序的结果是 10、2、20、9。比较过程就像查字典:先比第一个字符,"1" 最小所以 10 在最前;"2" 和 "20" 第一位相同,短的排前面;"9" 最大排最后。所以这不是 10 和 9 的特例,只要数字位数不一样,默认排序基本都会出错。 示例里用 [...values] 先复制了一份,是因为 sort() 会直接修改原数组。

比较器为什么不能返回布尔值

很多人会写 arr.sort((a, b) => a > b),在一些小数组上看起来也对,但这是错的写法。

比较器要表达三种结果:a 在前、b 在前、两者相等。布尔值转成数字只有 1 和 0,没有负数,引擎永远得不到「a 应该在前」这个信号。结果取决于引擎用的排序算法和数据的初始顺序,换个数据或换个浏览器就可能排错。

对象数组按字段排序
业务里更多的是给对象数组排序,比如商品按价格升序:goods.sort((a, b) => a.price - b.price)。价格相同想再按销量降序,就在返回 0 的时候接着比:a.price - b.price || b.sales - a.sales。 字符串字段不能用减法,减出来是 NaN。按姓名排序用 a.name.localeCompare(b.name),它会按语言习惯比较,还能处理中文。
回答前,多想一步

容易答错的地方

以为数组里全是数字,sort() 就会按数字排
sort() 不关心元素是什么类型,没有比较函数就一律转字符串。哪怕数组里全是数字,也要显式传 (a, b) => a - b。
以为稳定排序就能保证数字顺序正确
ES2019 起 sort() 规定必须是稳定排序,意思是比较结果为 0 的元素保持原来的先后顺序。它只管相等元素的相对位置,不会改变「默认按字符串比较」这条规则。
数组里有 NaN 或 null 也直接减
a - b 只要一边是 NaN,结果就是 NaN,比较器等于没给出有效结论,排序结果会乱。null 减法时会变成 0,也未必是你想要的位置。有脏数据时要先过滤,或者在比较器里单独决定它们排前还是排后。
试着用自己的话回答

面试官还会怎么问?

数组里有 undefined 会排在哪?

不管用不用比较函数,undefined 都不参与比较,统一放到数组最后,空位排在 undefined 后面。比较函数根本不会收到 undefined。

sort 和 toSorted 怎么选?

两者比较规则完全一样。区别是 sort() 改原数组并返回原数组,toSorted() 返回一个排好序的新数组,原数组不动。toSorted 是 ES2023 新增的,老环境要先确认支持,不支持就用 [...arr].sort()。

中文或带数字的文件名怎么排?

默认排序会把 "file10" 排在 "file2" 前面。用 Intl.Collator 并打开 numeric 选项就能按人的习惯排:arr.sort(new Intl.Collator('zh', { numeric: true }).compare)。中文按拼音排序同样可以用 localeCompare 或 Intl.Collator 指定语言。

从一道题,走向一组知识

把知识连起来

数组与集合

sort 会改原数组吗?不想改原数组该怎么排序?

这篇讲比较规则,那篇讲 sort 会直接改掉原数组,以及怎样排序又不动原数组。

数组与集合

Array.isArray 和 instanceof Array 有什么区别?为什么跨 iframe 就失效了?

排序前如果要确认拿到的真是数组,就会用到 Array.isArray 和 instanceof 的区别。

参考资料

  • MDN:sort

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

本题目录
  1. 先记住这个答案
  2. 同一组数字,两种排法
  3. 比较器为什么不能返回布尔值
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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