tosorted 的不可变性源于其设计上拒绝修改原数组,内部创建新副本排序后返回,原始数组的引用、内容及稀疏性均保持不变;它不提供就地选项,返回全新引用,与 sort() 的原地修改和返回原引用有本质区别。

toSorted 的不可变性不是“魔法”,而是设计上明确拒绝修改原数组——它内部必然创建一个新数组副本,再对这个副本排序,最后返回它。原始数组的内存地址、引用、内容全部保持原样,连稀疏性(如 [1, , 3] 中的空位)也一并保留。
为什么它不改原数组?关键在语义与实现分离
不同于 sort() 是就地算法(直接操作原数组内存),toSorted() 的规范要求必须返回新数组。这意味着:
- 每次调用都触发一次浅拷贝(类似
slice()),但底层引擎(如 V8)可能做优化,对小数组跳过显式拷贝步骤 - 即使传入比较函数,也只是作用于副本,不影响原数组任何一项
- 它不提供“就地”选项——没有类似
toSorted({ inplace: true })这样的参数,从 API 层面杜绝副作用可能
和 sort() 的本质区别:返回值即意图
sort() 返回的是原数组引用,你拿到的还是那个对象;toSorted() 返回的是全新数组引用,哪怕内容相同,=== 比较也一定为 false。这种差异在 React 等框架中直接影响渲染逻辑:
- 用
sort()后,state 引用没变但内容变了 → 可能跳过重渲染或触发意外更新 - 用
toSorted(),state 引用变了 → React 能正确识别变化,按预期响应
它真的完全“无副作用”吗?注意边界情况
不可变仅针对数组本身结构。如果数组里存的是对象,toSorted() 不会深拷贝这些对象:
- 排序过程不会修改对象属性,这是安全的
- 但后续若通过
sorted[0].name = 'new'修改,仍会影响原数组对应项——因为对象引用被共享 - 遇到
undefined或NaN时,不同引擎排序行为可能不一致,建议提前过滤或映射处理
兼容性不是原理,但影响你能否真正用上它
不可变是语言规范定义的行为,不是运行时补丁。但在旧环境(如 Node.js 18、Safari 16.3 以下)中,toSorted 根本不存在。此时若强行调用会报错,而非降级为不可变行为。所以实际使用时,需配合运行时检测或 polyfill:
- 推荐降级写法:
arr.toSorted?.(cb) ?? [arr].sort(cb) - 注意
[arr].sort()也是浅拷贝,语义等价,只是写法略长
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











