JavaScript的sort()不传比较函数时按字符串Unicode码点排序,非数字大小排序;如[10,2,33,1].sort()得[1,10,2,33],因"10"<"2";含负数、混合类型时更明显。

JavaScript 的 sort() 方法在不传比较函数时,根本不会按数字大小排序——它会把每个数字先转成字符串,再按 Unicode 码点逐字符比较。这不是 Bug,而是 ECMAScript 规范明确定义的行为(ECMA-262 §23.1.3.27)。但对开发者来说,结果常“反直觉”,容易误判为错误。
看排序结果是否出现“字典序错位”
这是最直接的识别方式:只要数组中存在两位及以上数字,且结果里有明显数值顺序颠倒,就基本可判定是字符串化排序在起作用。
-
[10, 2, 33, 1].sort()→[1, 10, 2, 33]:10 排在 2 前面,因为"10"首字符"1"(U+0031)小于"2"(U+0032) -
[23, 12, 8, 9].sort()→[12, 23, 8, 9]:所有以"1"开头的数都排在以"2"或"8"开头的数前面 - 含负数时更明显:
[-5, 10, -12].sort()→[-12, -5, 10],因为"-12"和"-5"的首字符"-"(U+002D = 45)比所有数字字符都小
检查数组是否含混合类型或特殊值
默认排序会统一调用 ToPrimitive → ToString,所以任何非纯字符串元素都会暴露问题:
-
[undefined, 1, null, '2'].sort()→[1, '2', null, undefined]:undefined转为"undefined",null转为"null",参与字符串比较 -
[1.5, 10.2, 2].sort()→[1.5, 10.2, 2]:因"1.5" < "10.2"(第二字符"."U+002E = 46 "0" U+0030 = 48) - 大小写混排字符串也会出错:
['Apple', 'banana', 'Cherry'].sort()→['Apple', 'Cherry', 'banana'],因大写字母 Unicode 值普遍小于小写
用 toString() 模拟验证
手动将数组每项转字符串,再按字典序排序,如果结果和 sort() 输出一致,就确认是默认行为在生效:
- 原数组:
[100, 21, 5, -7] - 转字符串:
["100", "21", "5", "-7"] - 字典序排列:
["-7", "100", "21", "5"]→ 对应数值:[-7, 100, 21, 5] - 执行
[100, 21, 5, -7].sort(),结果若完全匹配,即证实机制
注意 TypeScript 无法捕获该问题
即便数组类型标注为 number[],TypeScript 也不会报错或警告——它不校验运行时行为。编译通过不代表逻辑正确。实际执行仍走字符串路径,类型系统对此“视而不见”。

















