现代JavaScript的16个实用新特性:从ES2022到ES2025

更新日期: 2026-04-02 阅读: 14 标签: 特性

一、ES2022:填补日常痛点

1. Error.cause

写程序的人,谁没遇到过这种场景:一个错误引发了另一个错误,另一个错误又被新的包装吞掉,最后你排查半天,真正最初的原因早就找不到了。

以前遇到这种情况,我们通常只能二选一:要么直接覆盖原始错误,要么手动往错误对象上挂一堆自定义属性。能用,但不优雅。

现在有了Error.cause,这件事终于正规化了:

throw new Error("加载用户数据失败", {
  cause: realError
});

示例:

try {
  await fetchUser();
} catch (err) {
  throw new Error("用户加载失败", { cause: err });
}

这样做最大的好处是错误上下文不会断。出问题时,你能顺着整条链往回追,而不是看着一层层包装过的报错发呆。

2. Object.hasOwn()

以前我们想判断某个属性到底是不是对象“自己”的,而不是从原型链上继承来的,通常会这么写:

Object.prototype.hasOwnProperty.call(obj, "key");

现在简单多了:

Object.hasOwn(obj, "key");

示例:

const user = { name: "John" };

Object.hasOwn(user, "name");     // true
Object.hasOwn(user, "toString"); // false

这种变化看似很小,但恰恰就是这种“小而准”的API,最能改善日常写代码时的负担。

3. 顶层await

以前在模块最外层你是不能直接写await的。这就导致一个尴尬的情况:明明只是做一点启动初始化,比如加载配置、连数据库、读环境文件,你还得专门包一层async function init(){},然后再自己调用。

现在你可以直接这么写:

const config = await fetchConfig();
startApp(config);

示例1:数据库连接

const db = await connectToDatabase();
const users = await db.getUsers();

示例2:动态导入

const { default: heavyLib } = await import("./heavy-lib.js");
heavyLib.run();

示例3:读取环境配置

const settings = await loadSettingsFromFile();
console.log("应用启动配置:", settings);

顶层await的意义在于减少了那种为了迎合语言限制,不得不写的结构性废话。

4. 私有类字段#

JavaScript以前根本谈不上真正意义上的“私有字段”。我们顶多是这样自欺欺人:

class User {
  constructor(id) {
    this._id = id; // 只是约定,不是保护
  }
}

现在终于有了真正的私有字段:

class User {
  #id;

  constructor(id) {
    this.#id = id;
  }

  getId() {
    return this.#id;
  }
}

如果你在类外面直接写user.#id,会是语法错误,不是运行时报错。

示例:私有方法

class Counter {
  #count = 0;

  #increment() {
    this.#count++;
  }

  increase() {
    this.#increment();
  }
}

很多bug从来都不是因为功能不会写,而是因为“本来不该被碰的东西,被碰了”。

5. .at():相对索引访问

经典面试题:怎么拿数组最后一个元素?

以前:

arr[arr.length - 1];

现在:

arr.at(-1);

想取最后一个就-1,倒数第二个就-2,语义比算术更直接。


二、ES2023:朝着更安全的数据处理再走一步

6. toSorted()

Array.prototype.sort()会直接修改原数组。以前我们只好养成“先复制再排序”的习惯:

[...arr].sort();

现在可以直接写:

const sorted = arr.toSorted();

示例:

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

console.log(numbers); // [3, 1, 2]
console.log(sorted);  // [1, 2, 3]

这代表JavaScript越来越明显地鼓励一种更稳妥的写法:尽量少突变,多返回新值。

7. toReversed()和toSpliced()

和toSorted()一样,这两个方法延续的是同一个思路:复制,而不是原地修改。

arr.toReversed();  // 反转,不改原数组
arr.toSpliced(2, 1); // 截取,不改原数组

示例:

const items = [1, 2, 3, 4];

const reversed = items.toReversed();
const updated = items.toSpliced(1, 1);

console.log(items);    // [1, 2, 3, 4]
console.log(reversed); // [4, 3, 2, 1]
console.log(updated);  // [1, 3, 4]

如果你写React、Vue,或者任何稍微依赖状态不可变的数据流,这种方法真的很香。

8. findLast() / findLastIndex()

以前要找最后一个符合条件的元素,很多人会这么写:

[...arr].reverse().find(fn);

现在可以直接写:

arr.findLast(fn);
arr.findLastIndex(fn);

示例:

const numbers = [1, 4, 7, 4, 9];

numbers.findLast(n => n > 3);      // 9
numbers.findLastIndex(n => n > 3); // 4


三、ES2024:更聪明的数据组织与异步控制

9. Object.groupBy()

以前你要把数组按某个字段分组,最常见的写法是reduce():

users.reduce((acc, user) => {
  (acc[user.role] ??= []).push(user);
  return acc;
}, {});

现在简单成了一句:

const grouped = Object.groupBy(users, u => u.role);

示例:

const users = [
  { name: "John", role: "admin" },
  { name: "Jane", role: "user" },
  { name: "Bob", role: "admin" }
];

const grouped = Object.groupBy(users, u => u.role);
// { admin: [...], user: [...] }

10. Promise.withResolvers()

以前需要在Promise外部控制完成时机时,写法通常长这样:

let resolve;
const promise = new Promise(r => {
  resolve = r;
});

现在可以直接:

const { promise, resolve, reject } = Promise.withResolvers();

示例:

const { promise, resolve } = Promise.withResolvers();

setTimeout(() => resolve("Done!"), 1000);

await promise; // "Done!"

11. 可调整大小的ArrayBuffer

以前ArrayBuffer长度一旦创建就固定了。现在可以这样创建:

const buffer = new ArrayBuffer(8, {
  maxByteLength: 16
});

buffer.resize(12); // 动态调整大小


四、ES2025:函数式风格越来越像主流

12. 迭代器辅助方法(Iterator Helpers)

数组方法每调用一步,往往都会生成一个新的中间数组。数据量大时,这意味着额外的分配和处理成本。

现在,迭代器辅助方法提供了一种更“懒”的处理方式:

const result = iterator
  .map(x => x * 10)
  .filter(x => x > 80)
  .take(5)
  .toArray();

在真正需要结果之前,它不会急着把所有东西都算出来。

13. 新的Set方法

以前对两个Set做交集、并集、差集,写法通常都不太优雅:

const intersection = new Set([...a].filter(x => b.has(x)));
const union = new Set([...a, ...b]);

现在可以直接写:

a.intersection(b); // 交集
a.union(b);        // 并集
a.difference(b);   // 差集

示例:

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

a.intersection(b); // Set {2, 3}
a.union(b);        // Set {1, 2, 3, 4}
a.difference(b);   // Set {1}

14. RegExp.escape()

如果用用户输入去动态构造正则,用户输入里只要带了*、.、(、[之类的特殊字符,正则要么失效,要么行为完全变味。

以前大家通常会自己写一个转义工具函数。现在终于有了内建方案:

const regex = new RegExp(RegExp.escape(input));

15. Promise.try()

有的函数是同步的会直接throw,有的函数是异步的会返回rejected promise。以前想统一处理这两种错误,代码常常会有点别扭。

现在可以直接:

await Promise.try(() => mightThrow())

不管它是正常返回还是中途抛错,最后都会被统一包装进Promise流程里。

示例:

await Promise.try(() => JSON.parse(input))
  .then(process)
  .catch(handleError);

16. Float16Array

JavaScript默认数字是64位浮点数。在某些对性能、内存、传输体积更敏感的场景里,64位其实是有点“奢侈”的。

现在支持更小的半精度浮点数组:

const data = new Float16Array(1000);
类型位数
Float64Array64位
Float32Array32位
Float16Array16位

最后

如果你稍微退一步,不只盯着单个API,而是把这些年JavaScript的变化放在一起看,你会发现它其实在往同一个方向收拢:

  • 更少的突变

  • 更明确的表达

  • 更安全的异步控制

  • 更自然的函数式数据处理

  • 更接近日常开发真实需求的默认能力

JavaScript现在已经不太像从前那样,隔三差五就来一次“很大、很响、很容易上头”的革命了。但回头一看,很多以前自己手动填的坑,原来JavaScript已经悄悄替你填掉了。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13563

相关推荐

Html5、Css3、ES6的新特性

Html5的新特性语义化标签:有利于SEO,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重。表单新特性,多媒体视频(video)和音频(audio)

Js的用途和特性

JavaScript 最初的目的是为了“赋予网页生命”。这种编程语言我们称之为脚本。它们可以写在 HTML 中,在页面加载的时候会自动执行。脚本作为纯文本存在和执行。它们不需要特殊的准备或编译即可运行。

Angular 8的新特性介绍

在今天早些时候Angular团队发布了8.0.0稳定版。其实早在NgConf 2019大会上,演讲者就已经提及了从工具到差分加载的许多内容以及更多令人敬畏的功能。下面是我对8.0.0一些新功能的简单介绍,希望可以帮助大家快速了解新版本

Js即将到来的3个新特性

Optional Chaining(可选链式调用);Nullish coalescing(空值合并);Pipeline operator(管道运算符)通过三个函数对字符串进行处理;

CSS新特性contain,控制页面的重绘与重排

contain 属性允许我们指定特定的 DOM 元素和它的子元素,让它们能够独立于整个 DOM 树结构之外。目的是能够让浏览器有能力只对部分元素进行重绘、重排,而不必每次都针对整个页面。

ES2019 新特性汇总

最近 ECMAScript2019,最新提案完成:tc39 Finished Proposals,我这里也是按照官方介绍的顺序进行整理,如有疑问,可以查看官方介绍啦~另外之前也整理了 《ES6/ES7/ES8/ES9系列》,可以一起看哈。

ES9(2018)新特性:异步迭代、Promise.finally、Rest/Spread等

ES9是ECMA协会在2018年6月发行的一个版本,因为是ECMAScript的第九个版本,所以也称为ES9。本篇文章介绍ES2018(ES9)的新特性,来看看怎么使用它们。

解密HTTP/2与HTTP/3 的新特性

HTTP/2 相比于 HTTP/1.1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性能优化工作,当然兼容问题以及如何优雅降级应该是国内还不普遍使用的原因之一。

十个超级实用的 JS 特性

你可能刚上手 JavaScript,或者只是曾经偶尔用过。不管怎样,JavaScript 改变了很多,有些特性非常值得一用。 这篇文章介绍了一些特性,在我看来,一个严肃的 JavaScript 开发者每天都多多少少会用到这些特性

ES6新特性--var、let、const

var不存在块级作用域,具有变量提升机制。 let和const存在块级作用域,不存在变量提升。在同一作用域内只能声明一次。const在声明时需要赋值且无法修改,但如果常量是对象,则对象的属性可以修改。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!