1.Class Fields

  1. // 在ES2022之前,给class定义一个字段,我们要在constructor里定义:
  2. class X {
  3. constructor() {
  4. this.a = 123;
  5. }
  6. }
  7. // ES2022允许我们直接这么写:
  8. class X {
  9. a = 123;
  10. }

公共字段和私有字段如果没有被初始化赋值,则会默认设置为undefined。

  1. class X {
  2. a;
  3. #b;
  4. getB() {
  5. console.log(this.#b);
  6. }
  7. }
  8. x = new X();
  9. x.a // undefined
  10. x.getB() // undefined

对于多个class继承,如果一个字段在多个class上都有定义,那么会以最近的class定义为准。(靠近原则)

  1. class A {
  2. a = 1;
  3. }
  4. class B extends A {
  5. a;
  6. }
  7. const b = new B();
  8. b.a // undefined
  9. class C {
  10. a;
  11. }
  12. class D extends C {
  13. a = 1;
  14. }
  15. const d = new D();
  16. d.a // 1

公共字段都是通过Object.defineProperty创造的。当某一个字段,get、set也同时存在时,TC39委员会经过漫长的讨论,最终决定用Object.defineProperty的get、set默认行为,而不是class里定义的get和set。

  1. class A {
  2. set x(value) { console.log(++value); }
  3. get x() { return 'x' }
  4. }
  5. class B extends A {
  6. x = 1;
  7. }
  8. const b = new B();
  9. b.x; // 1 (并不会返回'x')
  10. b.x = 2; // 控制台不会打印3

在ES2022之前,并没有实际意义上的私有字段。大家形成一种默契,通常用下划线_开头的字段名来表示私有字段,但是这些字段还是可以手动更改的。
ES2022给我们提供了更加安全便捷的私有字段定义方法,就是以#开头命名的字段,都会被当成私有字段,在class外部是没办法直接读取、修改这些私有字段的。

  1. class X {
  2. #a = 123;
  3. b = 2;
  4. }
  5. const x = new X();
  6. x.b; // 2
  7. x.#a; // Uncaught SyntaxError: Private field '#a' must be declared in an enclosing class

2.RegExp Match Indices

正则表达式增加了一个/d修饰符,当使用正则表达式的exec()方法时,如果有/d修饰符,那么结果会多返回一个indices属性,用来表示匹配的结果的在原字符串中的起始index值。

  1. const re1 = /a+/d;
  2. const s1 = "aaaabbb";
  3. const m1 = re1.exec(s1);
  4. m1.indices[0] //[0, 3];

如果正则表达式中有具名捕获组,那么indices[1]则表示捕获组的起始index值,indices.groups同样记录了捕获组信息。

  1. const re1 = /a+(?<B>b+)/d;
  2. const s1 = "aaabbbccc";
  3. const m1 = re1.exec(s1);
  4. m1.indices[1] //[3, 6];
  5. m1.indices.groups //{ B: [3, 6] };

3.Top-level await

之前我们使用await时,必须使用async包裹起来,新的提案允许我们直接使用await;

4.Ergonomic brand checks for Private Fields

私有字段检测,之前在判断一个对象里有没有某个私有字段,是比较麻烦的,因为在访问对象上一个不存在的私有属性时,会抛出异常。通常用try/catch确保方法不会报错。
ES2022新提案中,可以用in操作符来判断对象中是否存在某个私有字段、私有方法或者getter。

5. .at()

新增的取值方法,可作用于Array, String, TypedArray。
.at()接收一个参数,对于数组array=[1, 2, 3]

  • 当参数是正数n时,结果跟直接获取数组的第n个元素array[n]一样
  • 当参数是负数-n时,相当于倒取第n个元素,等同于array[-n + array.length],
  • 当参数是其它值或者空时,直接返回数组第一个元素
    1. const arr = [1, 2, 3, 4, 5];
    2. arr.at(1) // 2
    3. arr.at(-1) // 5
    4. arr.at(-10) // undefined
    5. arr.at('aaaa') // 1
    6. arr.at() // 1

6.Error Cause

之前,我们在封装错误信息时,比较繁琐,没有统一的字段的表示错误原因。
新提案在Error构造函数新增了一个可选参数cause,允许我们在实例化Error时,将错误原因以参数形式传入,省去了我们自己单独处理的成本。

  1. async function doJob() {
  2. const rawResource = await fetch('//domain/resource-a')
  3. .catch(err => {
  4. throw new Error('Download raw resource failed', { cause: err });
  5. });
  6. const jobResult = doComputationalHeavyJob(rawResource);
  7. await fetch('//domain/upload', { method: 'POST', body: jobResult })
  8. .catch(err => {
  9. throw new Error('Upload job result failed', { cause: err });
  10. });
  11. }
  12. try {
  13. await doJob();
  14. } catch (e) {
  15. console.log(e);
  16. console.log('Caused by', e.cause);
  17. }
  18. // Error: Upload job result failed
  19. // Caused by TypeError: Failed to fetch