JavaScript 现代特性速览:ES2023 到 ES2026
JavaScript 的演进比大多数人印象中更快:ECMAScript 现在每年 6 月发布一个新版本,且大量实用特性不再需要等待"大版本",而是逐个落地并快速进入 Baseline。对前端工程师而言,掌握这些原生能力,可以显著减少对第三方工具库的依赖,也让代码更易读、更接近语言本身的设计意图。
这些能力是前端搭建的日常基础。搭配TypeScript 实战指南使用体验最佳;若想了解工程化侧的工具链,可阅读前端工具链 2026。
数组与对象的"复制式"方法
ES2023 引入了 Change Array by Copy 系列(MDN 已标记为 Baseline Widely available):toSorted()、toReversed()、toSpliced()、with()。它们与 sort/reverse/splice 对应,但不修改原数组、返回新数组,让不可变更新(配合 React、Zustand 等)写起来更顺手:
const months = ['Mar', 'Jan', 'Feb', 'Dec'];
const sorted = months.toSorted(); // ['Dec', 'Feb', 'Jan', 'Mar']
const reversed = months.toReversed();
const next = months.with(0, 'May'); // 替换索引 0 的元素
console.log(months); // 原数组不变
ES2024 又补齐了 Object.groupBy() 与 Map.groupBy(),按回调返回的键对数组分组,替代手写 reduce 分组逻辑:
const byGrade = Object.groupBy(students, s => s.score >= 60 ? 'pass' : 'fail');
四者的对应关系可以这样记忆:在新方法名前加 to,或用 with 替代直接索引赋值。它们都返回新数组、原数组保持不变;Map.groupBy 与 Object.groupBy 的唯一区别是返回 Map 而非普通对象,适合需要保留数字键或自定义键类型的场景。
| 旧方法 | 新复制式方法 | 返回 |
|---|---|---|
sort() |
toSorted() |
新数组 |
reverse() |
toReversed() |
新数组 |
splice() |
toSpliced() |
新数组 |
arr[i] = v |
with(i, v) |
新数组 |
异步与 Promise 相关增强
Promise.withResolvers()(ES2024):一次调用同时拿到 promise、resolve、reject,避免在构造器外无法解析的"回调外包"问题;Promise.try()(ES2025):把"可能同步、也可能异步"的函数统一包成 Promise,无需async包裹,错误处理更一致;Array.fromAsync()(ES2024):从异步可迭代对象(如流式接口)直接构造数组。
正则与字符串增强
v标志(unicodeSets,ES2024):字符串属性、集合差集/交集/并集等更强大的字符类运算,例如[\p{Script=Han}&&\p{Letter}]取汉字且为字母的字符;RegExp.escape()(ES2025):转义用户输入,避免在动态构造正则时破坏语法;String.prototype.isWellFormed()/toWellFormed()(ES2024):检测与修复孤立代理项,处理来自外部系统的乱码字符串;JSON.parse支持带source选项(ES2025),可还原原始文本。
迭代器与工具方法
ES2025 的 Iterator Helpers 让迭代器终于拥有 map/filter/take/drop/reduce/toArray 等方法,配合生成器可写出更声明式的数据流:
function* fib() { /* ... */ }
const first10 = [...fib()].filter(n => n % 2 === 0).toArray();
注意原生 Array.prototype.filter 返回数组,而迭代器版本返回新的迭代器,可继续链式调用,配合 take(5) 还能做到惰性计算。
值得关注的 TC39 提案
截至 2026 年中,以下提案处于 Stage 3(接近落地)或 Stage 2.7,值得提前了解(详见 TC39 proposals 仓库):
- Stage 3:
Iterator相关(chunking、join、includes)、正则缓冲区边界\A/\z/\Z、Error Stack Accessor、Await Dictionary、动态代码品牌检查; - Stage 2.7:Decorators(装饰器,含元数据)、
ShadowRealm(隔离的 JS 执行环境)、ESM Phase Imports、不可变ArrayBuffer; - Stage 2:管道操作符、
Math.clamp()、Iterator.range()、JSON.parseImmutable()、Structs、Amount(任意精度十进制金额)等; - Temporal:日期时间提案,目前处于 Stage 3,目标是取代
Date的不合理设计,提供时区、日历、Duration 等完善的时间 API,适合日期敏感的应用提前调研。
如何在项目中安全采用
- 看 Baseline 标记:MDN 对每个特性标注 "Baseline Widely available",未达标前不直接用于生产;
- 交给编译器:Babel/TypeScript 会把较新语法转译到旧环境,
core-js负责 polyfill 缺失的内置方法(如toSorted); - 按需引入:能用
Object.groupBy就不引 lodash 的分组函数,减小包体积; - 配合 TS 类型:TypeScript 的
lib配置会同步暴露新方法的类型定义(详见TypeScript 指南)。
参考:https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility
一个真实场景:状态更新与数据管道
把新特性放进真实代码里最能体会价值。以 React 的状态更新为例,过去"不改原数组"需要先拷贝再修改,现在用复制式方法直接写:
const [items, setItems] = useState(['Mar', 'Jan', 'Feb']);
// 排序,但不影响原数组
const sorted = items.toSorted();
// 替换某个索引
setItems(items.with(1, 'May'));
配合 Object.groupBy,一次请求拿到的数据可以先分组再渲染,不必引入 lodash:
const orders = await fetch('/api/orders').then(r => r.json());
const byStatus = Object.groupBy(orders, o => o.status);
// byStatus = { paid: [...], pending: [...], refunded: [...] }
迭代器方法在处理"无限流"时尤其有用:take 让管道在拿到足够数据后自动停止,不必先展开整个序列。比如从分页接口里懒加载,处理完一页即可 break,不用等全部数据落地。
常见问题
- 新特性在生产环境能用吗? 看 MDN 的 Baseline 标记。只要标注 "Baseline Widely available",主流浏览器就无需 polyfill;仍不放心可以用
core-js补齐后再上线。 toSorted和sort性能差多少? 复制式方法多一次数组拷贝,对百万级元素有可感知的开销;但绝大多数前端数据量远达不到这个规模,为了不可变性多花一点内存通常值得。Object.groupBy和手写reduce选哪个? 语义相同的前提下优先原生方法——代码更短、意图更清楚;只有需要自定义分组对象原型或做复杂聚合时才值得手写。- 升级新语法后老浏览器会崩吗? 语法层面交给 Babel/TS 转译,内置方法交给 polyfill;建议在 CI 里用
browserslist固定目标浏览器,让core-js按需自动注入。
16IDC 观察
语言特性每落地一批,前端代码的"基础设施负债"就少一分。对独立开发者与小型团队来说,优先吃透原生能力、再决定是否引入库,往往是包体积、可维护性与招聘门槛之间的最佳平衡点。做多语言站点时,Intl 与 Temporal 这类标准 API 尤其值得优先掌握。