toreversed() 是 es2023 新增的不可变数组反转方法,返回新数组而不修改原数组;reverse() 则就地修改原数组。两者均只浅层反转,且浏览器兼容性需注意。

toReversed 是什么,它和 reverse 有什么根本区别
toReversed() 是 ES2023 新增的数组方法,返回一个**新数组**,内容是原数组元素的逆序排列;而 reverse() 直接修改原数组并返回它自身。这是不可变编程的关键分水岭——你调用 toReversed() 后,原数组的 length、索引值、引用地址全都不变。
常见错误现象:有人误以为 arr.toReversed().push(1) 能追加到反转结果里,其实不行——toReversed() 返回的是普通数组,但后续操作是否“安全”取决于你是否继续把它当不可变值用(比如再赋值给新变量,而不是复用旧引用)。
-
toReversed()不改变原数组,也不影响其他引用该数组的变量 -
reverse()是就地修改,所有持有该数组引用的地方都会看到变化 - 两者都只做浅层反转:嵌套数组或对象内部结构不会被递归翻转
浏览器兼容性与 polyfill 必须考虑的现实问题
Chrome 114+、Firefox 117+、Safari 17.4+ 支持 toReversed();Edge 基于新版 Chromium 也支持。但如果你的项目需兼容旧版 Safari(如 iOS 16.3 及更早)或微信内置浏览器(X5 内核),直接调用会抛出 TypeError: arr.toReversed is not a function。
实操建议:不要盲目加 polyfill 库(比如 core-js 的完整包会增大 bundle)。更轻量的做法是按需补丁:
if (!Array.prototype.toReversed) {
Array.prototype.toReversed = function() {
return this.slice().reverse();
};
}
注意:slice() + reverse() 组合虽符合语义,但性能略低于原生(多一次遍历),且 slice() 对稀疏数组处理行为与原生 toReversed() 一致(保留空位)。
和扩展运算符 [...arr].reverse() 对比,哪个更推荐
两者都能获得反转副本,但语义和边界行为不同:
-
[...arr].reverse()在遇到类数组(如arguments、NodeList)时会失败,因为展开运算符要求目标可迭代,而toReversed()只定义在Array.prototype上,天然只适用于真数组 -
toReversed()明确表达“我要不可变反转”,代码意图更清晰;[...arr].reverse()是技巧性写法,容易让协作者困惑“为什么不用toReversed” - 对含
undefined或空位的稀疏数组:toReversed()保留空位(如[1, , 3].toReversed()→[3, , 1]),而[...arr]会把空位转成undefined元素,再reverse()就变成[3, undefined, 1]
配合 reduce、map 等高阶函数使用时的典型陷阱
不可变不是终点,而是链式操作的前提。很多人想写 arr.filter(x => x > 0).toReversed().map(x => x * 2),这完全合法——但要注意:每一步都生成新数组,内存开销是线性的。如果数组很大(比如上万项),连续链式调用可能触发 V8 的优化禁用。
实操建议:
- 避免无意义中间变量:不要写
const reversed = arr.toReversed(); const doubled = reversed.map(...);,直接链式更清晰 - 若需多次复用反转结果,务必缓存:
const reversedArr = arr.toReversed();,别重复调用toReversed() -
toReversed()不改变数组的原型链,所以它能和自定义数组子类(如继承Array的类)一起工作,前提是子类没重写该方法
真正容易被忽略的是:不可变不等于无副作用。如果你在 map 回调里修改了外部状态,或者反转后传给某个会 mutate 的第三方函数(比如某些 UI 库的 setState 方法内部直接 push),数据不可变原则依然会被破坏。










