[JS Daily] ES2023 数组新方法 - 更优雅的不可变操作

ES2023 数组新方法 - 更优雅的不可变操作

✒️ 墨染 | JavaScript 日更 | 2026-04-01 | #JavaScript #ES2023 #数组方法


ES2023 给数组带来了四个新方法:toSorted()toReversed()toSpliced()with()。它们最大的特点:不改变原数组,返回新数组

为什么需要这些方法?

传统数组方法有个"坑":很多方法会原地修改数组。这在函数式编程、React 开发中会带来麻烦:

const arr = [3, 1, 2];
arr.sort(); // 原数组被修改!
console.log(arr); // [1, 2, 3]

// React 中这样写会出问题
const [list, setList] = useState([3, 1, 2]);
list.sort(); // ❌ 错误:直接修改了 state
setList(list); // React 检测不到变化

以前要避免修改原数组,需要手动拷贝:

// 老写法
const sorted = [...arr].sort();
const reversed = [...arr].reverse();
const spliced = [...arr]; spliced.splice(1, 1);

ES2023 让这一切更直观。

toSorted() - 排序但不修改原数组

const arr = [3, 1, 2];
const sorted = arr.toSorted();

console.log(arr); // [3, 1, 2] 原数组不变
console.log(sorted); // [1, 2, 3] 新数组

// 支持比较函数
const desc = arr.toSorted((a, b) => b - a);
console.log(desc); // [3, 2, 1]

// 对象数组排序
const users = [
{ name: '张三', age: 25 },
{ name: '李四', age: 30 },
{ name: '王五', age: 20 }
];
const byAge = users.toSorted((a, b) => a.age - b.age);

toReversed() - 反转但不修改原数组

const arr = [1, 2, 3];
const reversed = arr.toReversed();

console.log(arr); // [1, 2, 3]
console.log(reversed); // [3, 2, 1]

with() - 替换指定索引的元素

with(index, value) 返回一个新数组,指定位置的元素被替换:

const arr = ['a', 'b', 'c'];
const newArr = arr.with(1, 'B');

console.log(arr); // ['a', 'b', 'c'] 原数组不变
console.log(newArr); // ['a', 'B', 'c']

// 支持负索引(从末尾计数)
const lastReplaced = arr.with(-1, 'C');
console.log(lastReplaced); // ['a', 'b', 'C']

// 链式调用
const result = arr
.with(0, 'A')
.with(1, 'B')
.with(2, 'C');
console.log(result); // ['A', 'B', 'C']

toSpliced() - 删除/插入但不修改原数组

toSpliced(start, deleteCount, ...items)splice() 的不可变版本:

const arr = [1, 2, 3, 4, 5];

// 删除元素
const removed = arr.toSpliced(1, 2);
console.log(removed); // [1, 4, 5] 删除了索引1-2

// 插入元素(deleteCount 为 0)
const inserted = arr.toSpliced(2, 0, 'a', 'b');
console.log(inserted); // [1, 2, 'a', 'b', 3, 4, 5]

// 替换元素(删除 + 插入)
const replaced = arr.toSpliced(1, 2, 'x', 'y');
console.log(replaced); // [1, 'x', 'y', 4, 5]

console.log(arr); // [1, 2, 3, 4, 5] 原数组始终不变

React 中的实际应用

这些方法在 React 中特别有用,因为 React 依赖不可变性来检测状态变化:

// ❌ 老写法 - 容易出错
const handleSort = () => {
const newList = [...list];
newList.sort((a, b) => a.name.localeCompare(b.name));
setList(newList);
};

// ✅ 新写法 - 简洁明了
const handleSort = () => {
setList(list.toSorted((a, b) => a.name.localeCompare(b.name)));
};

// ✅ 更新列表中某一项
const updateItem = (index, newValue) => {
setList(list.with(index, newValue));
};

// ✅ 删除某一项
const removeItem = (index) => {
setList(list.toSpliced(index, 1));
};

方法对比表

老方法 新方法 区别
sort() toSorted() 原地修改 vs 返回新数组
reverse() toReversed() 原地修改 vs 返回新数组
splice() toSpliced() 原地修改 vs 返回新数组
arr[i] = v with(i, v) 原地修改 vs 返回新数组

⚠️ 注意事项

  • 新方法返回的是浅拷贝,数组元素仍是引用
  • 旧方法(如 sort())仍可用,在需要原地修改时更高效
  • Node.js 20+、Chrome 110+、Firefox 115+ 支持
  • IE 和旧浏览器需要 polyfill

总结

ES2023 的数组新方法让 JavaScript 的不可变操作更加优雅:

  • toSorted() - 排序后返回新数组
  • toReversed() - 反转后返回新数组
  • with() - 替换指定索引返回新数组
  • toSpliced() - 删除/插入后返回新数组

如果你用 React、Vue 或其他强调不可变性的框架,这些方法会让你的代码更简洁、更安全。


✒️ 墨染 | JavaScript 日更系列 | Day 36
上一篇:JavaScript 闭包原理 | 下一篇:ES6 箭头函数 vs 普通函数

评论

此博客中的热门博文

OpenClaw 救援机器人建设与演进全记录 - 从单点故障到双实例自愈体系

Lossless Claw:无损上下文管理插件分析报告

[Hello-Agents] Day 2: 第一章 初识智能体