使用 Array.prototype.toSorted 对比 sort 性能区别?

文章导读
Array.prototype.toSorted() 因需要创建数组副本,内存占用通常高于原地排序的 sort(),运行时间在大多数业务场景下差异可忽略,但在超大数组或内存敏感场景需警惕复制开销。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

Array.prototype.toSorted() 因需要创建数组副本,内存占用通常高于原地排序的 sort(),运行时间在大多数业务场景下差异可忽略,但在超大数组或内存敏感场景需警惕复制开销。

先说结论:toSorted() 牺牲少量性能换取数据安全性,适合 React 等不可变数据场景,不适合超大数组高频排序。

  • 适合:前端状态管理、函数式编程、需要保留原数组的场景
  • 重点看:数组长度、内存限制、浏览器兼容性(Chrome 117+、Node 20+)
  • 别忽略:toSorted() 是浅拷贝,对象数组元素引用仍共享,修改元素属性会影响原数组

命令速用版

直接调用 toSorted() 获取新数组,原数组不变;sort() 直接修改原数组并返回引用。

const arr = [3, 1, 2];
const sorted = arr.toSorted((a, b) => a - b); // 新数组 [1, 2, 3]
console.log(arr); // 原数组 [3, 1, 2]

const arr2 = [3, 1, 2];
const sorted2 = arr2.sort((a, b) => a - b); // 原数组被修改为 [1, 2, 3]

为什么会这样

toSorted() 性能开销主要来自数组复制,而非排序算法本身。

sort() 是原地算法(In-place),直接在原内存空间交换元素,额外内存分配少。toSorted() 必须先分配新内存空间复制原数组元素,再对新数组排序。公开资料中没有看到可靠的量化数据证明具体慢多少,但 V8 引擎文档提到底层实现可能对小数组做了 fast-path 优化,意味着在小数据量下性能损耗可能极低。

分步处理

根据数据规模和场景选择方法,避免盲目替换。

第一步:判断数据规模

如果数组长度小于 1000 项,toSorted() 的复制开销在现代设备上通常小于 1ms,可优先保证代码安全性。如果数组超过 10 万项,需警惕内存峰值。

第二步:检查兼容性

toSorted() 是 ES2023 特性。Chrome 117+、Firefox 120+、Safari 17.4+、Node.js 20.2+ 原生支持。旧环境需降级:

const sorted = arr.toSorted?.((a, b) => a - b) ?? [...arr].sort((a, b) => a - b);

第三步:确认对象引用

使用 Array.prototype.toSorted 对比 sort 性能区别?

如果数组元素是对象,toSorted() 仅复制引用。修改 sorted[0].name 仍会影响原数组对应项。需深拷贝时才用 structuredClone 等方案。

怎么验证是否生效

使用 Performance API 本地测试具体耗时,不要依赖理论数据。

console.time('toSorted');
const s1 = largeArray.toSorted((a, b) => a - b);
console.timeEnd('toSorted');

console.time('sort');
const s2 = [...largeArray].sort((a, b) => a - b);
console.timeEnd('sort');

对比两者耗时差值。如果差值稳定超过业务阈值(如 50ms),则在大数组场景回退到 sort() 配合展开运算符。

常见坑

兼容性报错:旧浏览器或 Node.js 18 及以下会报 TypeError: arr.toSorted is not a function,必须加降级处理。

浅拷贝陷阱:以为 toSorted() 是深拷贝,修改对象属性导致原数据污染。它只保证数组顺序不变,不保证元素内容隔离。

默认排序陷阱:不传比较函数时,toSorted() 默认按字符串 Unicode 码点排序,数字数组 [10, 2] 会变成 [10, 2] 而非 [2, 10],必须显式传 (a, b) => a - b。

常见问题

toSorted 比 sort 慢多少?

公开资料中没有看到可靠的量化数据,通常慢在数组复制环节,小数组差异可忽略。

React 中必须用 toSorted 吗?

不是必须,但推荐。它能避免直接修改 state 数组导致的渲染异常,符合不可变数据原则。

旧浏览器怎么兼容 toSorted?

使用 [...arr].sort() 替代,或引入 core-js polyfill,但需检测是否已存在该方法。

toSorted 支持对象数组排序吗?

支持,但必须传比较函数,如 (a, b) => a.price - b.price,否则按字符串排序会出错。

参考来源

  • ECMAScript 2023 新特性文档,Array.prototype.toSorted 方法说明
  • 浏览器兼容性文档,Chrome 117+、Firefox 120+、Safari 17.4+ 支持情况
  • 知识库资料:如何用 Array.prototype.toSorted() 在不改变原始数据顺序的前提下获取排序后的新副本
  • 知识库资料:如何利用 Array.prototype.toSorted()(ES2023) 实现符合 React 声明式更新的排序