JavaScript 中的 Array.prototype.sort 为何不总是按预期排序?
在开发中,我们经常用 `Array.prototype.sort()` 对数组排序,特别是处理数字数组时,默认行为常常让人困惑。比如 `[1, 5, 10, 2].sort()` 会得到 `[1, 10, 2, 5]`,而不是按数值大小排列。这是因为 `sort` 默认将元素转换为字符串,再比较 UTF-16 码元序列。更隐蔽的问题出现在比较函数返回值不规范、数组包含 `undefined` 或稀疏元素,以及现代引擎对稳定排序的差异上。本文从底层规范与常见误区出发,讨论排序不生效的原因、比较函数的正确写法、以及处理数字、对象、多字段排序时的可靠做法,同时涉及性能与稳定性的取舍。 ## 默认比较是字符串比较 `sort()` 不传参数时,会把所有元素转成字符串,然后按 UTF-16 码元顺序比较。数字 `10` 转成 `"10"`,`2` 转成 `"2"`,字符串比较中 `"10"` 的字符 `'1'` 排在 `'2'` 前面,所以 `10` 会出现在 `2` 之前。这个行为从 ES1 就定下来了,不能依赖它做数值排序。 ```js const nums = [1, 5, 10, 2]; nums.sort(); console.log(nums); // [1, 10, 2, 5] ``` 要按数值排序,必须提供比较函数。 ```js nums.sort((a, b) => a - b); console.log(nums); // [1, 2, 5, 10] ``` ## 比较函数返回值的要求 比较函数应该返回一个数字: - 小于 0:`a` 排在 `b` 前面 - 大于 0:`b` 排在 `a` 前面 - 等于 0:保持相对顺序(在稳定排序下) 很多人会写成返回布尔值或者直接返回差值却忽略浮点数精度。例如 `return a > b` 只会返回 `true` 或 `false`,被隐式转换为 `1` 或 `0`,导致 `a a > b); // 结果不可靠 // 正确:返回数值 [3, 1, 2].sort((a, b) => a - b); ``` 对于可能超出安全整数的数字,用 `a - b` 也可能溢出或丢失精度,更安全的是用比较运算符返回 -1 / 0 / 1。 ```js function compareNumbers(a, b) { if (a b) return 1; return 0; } ``` ## undefined、null 和稀疏元素 `undefined` 元素会被 `sort` 一律排到数组末尾,比较函数也不会被调用。`null` 则会被转换成字符串 `"null"`。稀疏数组中的空槽会被当作 `undefined` 处理,并且排序后空槽可能被具体值填充,改变数组长度。 ```js const arr = [3, undefined, 1, null, 2]; arr.sort((a, b) => a - b); console.log(arr); // [1, 2, 3, null, undefined] ``` 如果数据来自 JSON 或接口,字段可能缺失,最好先过滤或映射为统一类型再排序。 ## 对象数组和多字段排序 按对象属性排序时,要确保属性可比较且类型一致。混合字符串和数字时,`a - b` 会得到 `NaN`,比较函数返回 `NaN` 被当作 0,排序失效。 ```js const users = [ { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }, { name: 'Carol', age: 30 } ]; users.sort((a, b) => a.age - b.age); ``` 多字段排序可以用链式比较,先比较主要字段,相等时再比较次要字段。 ```js users.sort((a, b) => { if (a.age !== b.age) return a.age - b.age; return a.name.localeCompare(b.name); }); ``` `localeCompare` 适合字符串比较,能处理语言敏感的大小写和变音符号。 ## 稳定排序与引擎差异 ES2019 之前,规范不要求 `sort` 稳定,V8 对短数组用插入排序(稳定),长数组用快速排序(不稳定)。ES2019 起要求稳定排序,所有现代引擎都遵守。但稳定只保证比较函数返回 0 的元素相对顺序不变,如果比较函数本身设计有问题,依然会得到意外结果。 ```js const items = [ { id: 1, type: 'b' }, { id: 2, type: 'a' }, { id: 3, type: 'b' } ]; items.sort((a, b) => a.type.localeCompare(b.type)); // id 为 1 和 3 的元素都会保持原有相对顺序 ``` ## 性能与拷贝 `sort` 会直接修改原数组。如果不希望改变原数组,先用 `slice()` 或扩展运算符复制。 ```js const sorted = [...arr].sort((a, b) => a - b); ``` 比较函数应尽量简单,避免在函数内部做复杂计算或频繁访问闭包变量。对于大数组,可以先映射出排序键,排序后再映射回原对象,减少重复属性访问。 ```js const sorted = arr .map(item => ({ item, key: item.value })) .sort((a, b) => a.key - b.key) .map(entry => entry.item); ``` 如果只需要前 N 个元素,不必全量排序,可以用堆或选择算法,但多数场景下 `sort` 足够快。 ## 实际排查建议 遇到排序不符合预期,先检查比较函数返回值是否符合规范,再确认数组元素类型是否一致,有无 `undefined`、`null` 或数字字符串混合。用 `console.log` 在比较函数里打印参数和返回值是快速定位手段,但线上环境记得移除。单元测试里加几条边界用例,比如空数组、单元素、相同值、极端数值,能避免大部分低级错误。 推荐查看天气:https://www.40tianqi.com/jiancaoping/ 推荐查看天气:https://www.40tianqi.com/jiancaoping/zuotian.html 推荐查看天气:https://www.40tianqi.com/jiancaoping/7tian.html 推荐查看天气:https://www.40tianqi.com/jiancaoping/10tian.html 推荐查看天气:https://www.40tianqi.com/jiancaoping/15tian.html 推荐查看天气:https://www.40tianqi.com/jiancaoping/40tian.html 推荐查看天气:https://www.40tianqi.com/wanbailin/ 推荐查看天气:https://www.40tianqi.com/wanbailin/zuotian.html 推荐查看天气:https://www.40tianqi.com/wanbailin/7tian.html 推荐查看天气:https://www.40tianqi.com/wanbailin/10tian.html 推荐查看天气:https://www.40tianqi.com/wanbailin/15tian.html 推荐查看天气:https://www.40tianqi.com/wanbailin/40tian.html 推荐查看天气:https://www.40tianqi.com/jinyuan/ 推荐查看天气:https://www.40tianqi.com/jinyuan/zuotian.html 推荐查看天气:https://www.40tianqi.com/jinyuan/7tian.html 推荐查看天气:https://www.40tianqi.com/jinyuan/10tian.html 推荐查看天气:https://www.40tianqi.com/jinyuan/15tian.html 推荐查看天气:https://www.40tianqi.com/jinyuan/40tian.html 推荐查看天气:https://www.40tianqi.com/qingxu/ 推荐查看天气:https://www.40tianqi.com/qingxu/zuotian.html 推荐查看天气:https://www.40tianqi.com/qingxu/7tian.html 推荐查看天气:https://www.40tianqi.com/qingxu/10tian.html 推荐查看天气:https://www.40tianqi.com/qingxu/15tian.html 推荐查看天气:https://www.40tianqi.com/qingxu/40tian.html 推荐查看天气:https://www.40tianqi.com/yangqu/ 推荐查看天气:https://www.40tianqi.com/yangqu/zuotian.html 推荐查看天气:https://www.40tianqi.com/yangqu/7tian.html 推荐查看天气:https://www.40tianqi.com/yangqu/10tian.html 推荐查看天气:https://www.40tianqi.com/yangqu/15tian.html 推荐查看天气:https://www.40tianqi.com/yangqu/40tian.html 推荐查看天气:https://www.40tianqi.com/loufan/ 推荐查看天气:https://www.40tianqi.com/loufan/zuotian.html 推荐查看天气:https://www.40tianqi.com/loufan/7tian.html 推荐查看天气:https://www.40tianqi.com/loufan/10tian.html 推荐查看天气:https://www.40tianqi.com/loufan/15tian.html 推荐查看天气:https://www.40tianqi.com/loufan/40tian.html 推荐查看天气:https://www.40tianqi.com/gujiao/ 推荐查看天气:https://www.40tianqi.com/gujiao/zuotian.html 推荐查看天气:https://www.40tianqi.com/gujiao/7tian.html 推荐查看天气:https://www.40tianqi.com/gujiao/10tian.html 推荐查看天气:https://www.40tianqi.com/gujiao/15tian.html 推荐查看天气:https://www.40tianqi.com/gujiao/40tian.html 推荐查看天气:https://www.40tianqi.com/datongshi/ 推荐查看天气:https://www.40tianqi.com/datongshi/zuotian.html 推荐查看天气:https://www.40tianqi.com/datongshi/7tian.html 推荐查看天气:https://www.40tianqi.com/datongshi/10tian.html 推荐查看天气:https://www.40tianqi.com/datongshi/15tian.html 推荐查看天气:https://www.40tianqi.com/datongshi/40tian.html 推荐查看天气:https://www.40tianqi.com/nanjiao/ 推荐查看天气:https://www.40tianqi.com/nanjiao/zuotian.html 推荐查看天气:https://www.40tianqi.com/nanjiao/7tian.html 推荐查看天气:https://www.40tianqi.com/nanjiao/10tian.html 推荐查看天气:https://www.40tianqi.com/nanjiao/15tian.html 推荐查看天气:https://www.40tianqi.com/nanjiao/40tian.html 推荐查看天气:https://www.40tianqi.com/xinrong/ 推荐查看天气:https://www.40tianqi.com/xinrong/zuotian.html 推荐查看天气:https://www.40tianqi.com/xinrong/7tian.html 推荐查看天气:https://www.40tianqi.com/xinrong/10tian.html 推荐查看天气:https://www.40tianqi.com/xinrong/15tian.html 推荐查看天气:https://www.40tianqi.com/xinrong/40tian.html 推荐查看天气:https://www.40tianqi.com/yanggao/ 推荐查看天气:https://www.40tianqi.com/yanggao/zuotian.html 推荐查看天气:https://www.40tianqi.com/yanggao/7tian.html 推荐查看天气:https://www.40tianqi.com/yanggao/10tian.html 推荐查看天气:https://www.40tianqi.com/yanggao/15tian.html 推荐查看天气:https://www.40tianqi.com/yanggao/40tian.html 推荐查看天气:https://www.40tianqi.com/tianzhen/ 推荐查看天气:https://www.40tianqi.com/tianzhen/zuotian.html 推荐查看天气:https://www.40tianqi.com/tianzhen/7tian.html 推荐查看天气:https://www.40tianqi.com/tianzhen/10tian.html 推荐查看天气:https://www.40tianqi.com/tianzhen/15tian.html 推荐查看天气:https://www.40tianqi.com/tianzhen/40tian.html 推荐查看天气:https://www.40tianqi.com/datongguangling/ 推荐查看天气:https://www.40tianqi.com/datongguangling/zuotian.html 推荐查看天气:https://www.40tianqi.com/datongguangling/7tian.html 推荐查看天气:https://www.40tianqi.com/datongguangling/10tian.html 推荐查看天气:https://www.40tianqi.com/datongguangling/15tian.html 推荐查看天气:https://www.40tianqi.com/datongguangling/40tian.html 推荐查看天气:https://www.40tianqi.com/lingqiu/ 推荐查看天气:https://www.40tianqi.com/lingqiu/zuotian.html 推荐查看天气:https://www.40tianqi.com/lingqiu/7tian.html 推荐查看天气:https://www.40tianqi.com/lingqiu/10tian.html 推荐查看天气:https://www.40tianqi.com/lingqiu/15tian.html 推荐查看天气:https://www.40tianqi.com/lingqiu/40tian.html 推荐查看天气:https://www.40tianqi.com/hunyuan/ 推荐查看天气:https://www.40tianqi.com/hunyuan/zuotian.html 推荐查看天气:https://www.40tianqi.com/hunyuan/7tian.html 推荐查看天气:https://www.40tianqi.com/hunyuan/10tian.html 推荐查看天气:https://www.40tianqi.com/hunyuan/15tian.html 推荐查看天气:https://www.40tianqi.com/hunyuan/40tian.html 推荐查看天气:https://www.40tianqi.com/zuoyun/ 推荐查看天气:https://www.40tianqi.com/zuoyun/zuotian.html 推荐查看天气:https://www.40tianqi.com/zuoyun/7tian.html 推荐查看天气:https://www.40tianqi.com/zuoyun/10tian.html 推荐查看天气:https://www.40tianqi.com/zuoyun/15tian.html 推荐查看天气:https://www.40tianqi.com/zuoyun/40tian.html 推荐查看天气:https://www.40tianqi.com/datongxian/ 推荐查看天气:https://www.40tianqi.com/datongxian/zuotian.html 推荐查看天气:https://www.40tianqi.com/datongxian/7tian.html 推荐查看天气:https://www.40tianqi.com/datongxian/10tian.html 推荐查看天气:https://www.40tianqi.com/datongxian/15tian.html 推荐查看天气:https://www.40tianqi.com/datongxian/40tian.html 推荐查看天气:https://www.40tianqi.com/yangquan/ 推荐查看天气:https://www.40tianqi.com/yangquan/zuotian.html 推荐查看天气:https://www.40tianqi.com/yangquan/7tian.html 推荐查看天气:https://www.40tianqi.com/yangquan/10tian.html 推荐查看天气:https://www.40tianqi.com/yangquan/15tian.html 推荐查看天气:https://www.40tianqi.com/yangquan/40tian.html 推荐查看天气:https://www.40tianqi.com/kuangqu/ 推荐查看天气:https://www.40tianqi.com/kuangqu/zuotian.html 推荐查看天气:https://www.40tianqi.com/kuangqu/7tian.html 推荐查看天气:https://www.40tianqi.com/kuangqu/10tian.html 推荐查看天气:https://www.40tianqi.com/kuangqu/15tian.html 推荐查看天气:https://www.40tianqi.com/kuangqu/40tian.html 推荐查看天气:https://www.40tianqi.com/pingding/ 推荐查看天气:https://www.40tianqi.com/pingding/zuotian.html 推荐查看天气:https://www.40tianqi.com/pingding/7tian.html 推荐查看天气:https://www.40tianqi.com/pingding/10tian.html 推荐查看天气:https://www.40tianqi.com/pingding/15tian.html 推荐查看天气:https://www.40tianqi.com/pingding/40tian.html 推荐查看天气:https://www.40tianqi.com/yuxian/ 推荐查看天气:https://www.40tianqi.com/yuxian/zuotian.html 推荐查看天气:https://www.40tianqi.com/yuxian/7tian.html 推荐查看天气:https://www.40tianqi.com/yuxian/10tian.html 推荐查看天气:https://www.40tianqi.com/yuxian/15tian.html 推荐查看天气:https://www.40tianqi.com/yuxian/40tian.html 推荐查看天气:https://www.40tianqi.com/changzhi/ 推荐查看天气:https://www.40tianqi.com/changzhi/zuotian.html 推荐查看天气:https://www.40tianqi.com/changzhi/7tian.html 推荐查看天气:https://www.40tianqi.com/changzhi/10tian.html 推荐查看天气:https://www.40tianqi.com/changzhi/15tian.html 推荐查看天气:https://www.40tianqi.com/changzhi/40tian.html 推荐查看天气:https://www.40tianqi.com/xiangyuan/ 推荐查看天气:https://www.40tianqi.com/xiangyuan/zuotian.html 推荐查看天气:https://www.40tianqi.com/xiangyuan/7tian.html 推荐查看天气:https://www.40tianqi.com/xiangyuan/10tian.html 推荐查看天气:https://www.40tianqi.com/xiangyuan/15tian.html 推荐查看天气:https://www.40tianqi.com/xiangyuan/40tian.html 推荐查看天气:https://www.40tianqi.com/tunliu/ 推荐查看天气:https://www.40tianqi.com/tunliu/zuotian.html 推荐查看天气:https://www.40tianqi.com/tunliu/7tian.html 推荐查看天气:https://www.40tianqi.com/tunliu/10tian.html 推荐查看天气:https://www.40tianqi.com/tunliu/15tian.html 推荐查看天气:https://www.40tianqi.com/tunliu/40tian.html 推荐查看天气:https://www.40tianqi.com/pingshun/ 推荐查看天气:https://www.40tianqi.com/pingshun/zuotian.html 推荐查看天气:https://www.40tianqi.com/pingshun/7tian.html 推荐查看天气:https://www.40tianqi.com/pingshun/10tian.html 推荐查看天气:https://www.40tianqi.com/pingshun/15tian.html 推荐查看天气:https://www.40tianqi.com/pingshun/40tian.html 推荐查看天气:https://www.40tianqi.com/changzhilicheng/ 推荐查看天气:https://www.40tianqi.com/changzhilicheng/zuotian.html 推荐查看天气:https://www.40tianqi.com/changzhilicheng/7tian.html 推荐查看天气:https://www.40tianqi.com/changzhilicheng/10tian.html 推荐查看天气:https://www.40tianqi.com/changzhilicheng/15tian.html 推荐查看天气:https://www.40tianqi.com/changzhilicheng/40tian.html 推荐查看天气:https://www.40tianqi.com/huguan/ 推荐查看天气:https://www.40tianqi.com/huguan/zuotian.html 推荐查看天气:https://www.40tianqi.com/huguan/7tian.html 推荐查看天气:https://www.40tianqi.com/huguan/10tian.html 推荐查看天气:https://www.40tianqi.com/huguan/15tian.html 推荐查看天气:https://www.40tianqi.com/huguan/40tian.html 推荐查看天气:https://www.40tianqi.com/changzi/ 推荐查看天气:https://www.40tianqi.com/changzi/zuotian.html 推荐查看天气:https://www.40tianqi.com/changzi/7tian.html 推荐查看天气:https://www.40tianqi.com/changzi/10tian.html 推荐查看天气:https://www.40tianqi.com/changzi/15tian.html 推荐查看天气:https://www.40tianqi.com/changzi/40tian.html 推荐查看天气:https://www.40tianqi.com/wuxiang/ 推荐查看天气:https://www.40tianqi.com/wuxiang/zuotian.html 推荐查看天气:https://www.40tianqi.com/wuxiang/7tian.html 推荐查看天气:https://www.40tianqi.com/wuxiang/10tian.html 推荐查看天气:https://www.40tianqi.com/wuxiang/15tian.html 推荐查看天气:https://www.40tianqi.com/wuxiang/40tian.html 推荐查看天气:https://www.40tianqi.com/qinxian/ 推荐查看天气:https://www.40tianqi.com/qinxian/zuotian.html 推荐查看天气:https://www.40tianqi.com/qinxian/7tian.html 推荐查看天气:https://www.40tianqi.com/qinxian/10tian.html 推荐查看天气:https://www.40tianqi.com/qinxian/15tian.html 推荐查看天气:https://www.40tianqi.com/qinxian/40tian.html 推荐查看天气:https://www.40tianqi.com/qinyuan/ 推荐查看天气:https://www.40tianqi.com/qinyuan/zuotian.html 推荐查看天气:https://www.40tianqi.com/qinyuan/7tian.html 推荐查看天气:https://www.40tianqi.com/qinyuan/10tian.html 推荐查看天气:https://www.40tianqi.com/qinyuan/15tian.html 推荐查看天气:https://www.40tianqi.com/qinyuan/40tian.html 推荐查看天气:https://www.40tianqi.com/shuozhou/ 推荐查看天气:https://www.40tianqi.com/shuozhou/zuotian.html 推荐查看天气:https://www.40tianqi.com/shuozhou/7tian.html 推荐查看天气:https://www.40tianqi.com/shuozhou/10tian.html 推荐查看天气:https://www.40tianqi.com/shuozhou/15tian.html 推荐查看天气:https://www.40tianqi.com/shuozhou/40tian.html 推荐查看天气:https://www.40tianqi.com/shuocheng/ 推荐查看天气:https://www.40tianqi.com/shuocheng/zuotian.html 推荐查看天气:https://www.40tianqi.com/shuocheng/7tian.html 推荐查看天气:https://www.40tianqi.com/shuocheng/10tian.html 推荐查看天气:https://www.40tianqi.com/shuocheng/15tian.html 推荐查看天气:https://www.40tianqi.com/shuocheng/40tian.html 推荐查看天气:https://www.40tianqi.com/shuozhoupinglu/ 推荐查看天气:https://www.40tianqi.com/shuozhoupinglu/zuotian.html