tosorted() 不修改原数组,返回新数组,是纯函数;默认字符串排序,数字需传比较函数;兼容性有限,旧环境用[...arr].sort()替代;注意比较函数健壮性和性能优化。

toSorted() 本身就不会修改原数组
直接调用 toSorted() 就能得到新数组,原始数组完全不变——这是它和 sort() 最本质的区别。如果你发现原数组被改了,那大概率是误用了 sort(),或者在别处做了赋值覆盖。
常见错误现象:arr.sort((a, b) => a - b) 后发现 arr 顺序变了;或者写了 const sorted = arr.toSorted(); arr = sorted; 这种自我覆盖操作。
-
toSorted()是纯函数,无副作用,不接受任何“就地排序”选项 - 它默认按字符串 Unicode 码点升序,数字需显式传比较函数,否则
[10, 2, 1]会变成[1, 10, 2] - 不支持 IE,Chrome 91+、Firefox 91+、Safari 14.1+ 才有,旧环境需降级用
[...arr].sort(...)
正确写法:传比较函数处理数字/对象
默认行为对数字或复杂结构不可靠,必须自己控制排序逻辑。比如按对象的 price 升序:
const items = [{name: 'apple', price: 3.5}, {name: 'banana', price: 1.2}];
const sortedByPrice = items.toSorted((a, b) => a.price - b.price);
注意:a.price - b.price 依赖数值稳定性,如果字段可能为 null 或 undefined,要先做兜底(如 ?? 0)。
- 字符串忽略大小写:
(a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }) - 倒序直接翻转差值:
(a, b) => b.timestamp - a.timestamp - 多级排序需链式判断:
(a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name)
兼容性 fallback 要小心浅拷贝陷阱
在需要支持旧浏览器时,[...arr].sort(...) 是最常用替代,但要注意:它只做浅拷贝。
如果数组元素是对象,[...arr] 复制的是引用,后续修改 sorted[0].price 仍会影响原数组对应项。
- 真深拷贝不现实(性能差、循环引用报错),通常只需确保排序逻辑不修改元素自身
- 更安全的 fallback 写法:
arr.map(x => x).sort(...),语义清晰且与toSorted()行为对齐 - TypeScript 用户注意:老版
Array.prototype.sort返回this类型,而toSorted()返回T[],类型推导可能不同
别把 toSorted() 和 toReversed() 混一起用
有人想“先排再反”,写成 arr.toSorted().toReversed() ——这没问题,但多了一次遍历。如果只是要降序,直接在比较函数里翻转逻辑更高效。
错误示范:arr.toSorted((a, b) => b - a).toReversed(),相当于白跑一趟。
-
toSorted()和toReversed()都返回新数组,链式调用没问题,但没必要叠加语义 - 性能上,单次
toSorted()的时间复杂度是 O(n log n),两次数组创建 + 一次排序 + 一次反转 = O(n log n + 2n),能省则省 - 如果业务逻辑真需要“先按 A 排、再整体反转”,那就保持链式,但得清楚代价在哪
实际项目里最容易被忽略的是比较函数的健壮性——特别是后端返回字段缺失或类型不一致时,a?.value ?? 0 比裸写 a.value 更稳妥。










