1.Class Fields
// 在ES2022之前,给class定义一个字段,我们要在constructor里定义:class X {constructor() {this.a = 123;}}// ES2022允许我们直接这么写:class X {a = 123;}
公共字段和私有字段如果没有被初始化赋值,则会默认设置为undefined。
class X {a;#b;getB() {console.log(this.#b);}}x = new X();x.a // undefinedx.getB() // undefined
对于多个class继承,如果一个字段在多个class上都有定义,那么会以最近的class定义为准。(靠近原则)
class A {a = 1;}class B extends A {a;}const b = new B();b.a // undefinedclass C {a;}class D extends C {a = 1;}const d = new D();d.a // 1
公共字段都是通过Object.defineProperty创造的。当某一个字段,get、set也同时存在时,TC39委员会经过漫长的讨论,最终决定用Object.defineProperty的get、set默认行为,而不是class里定义的get和set。
class A {set x(value) { console.log(++value); }get x() { return 'x' }}class B extends A {x = 1;}const b = new B();b.x; // 1 (并不会返回'x')b.x = 2; // 控制台不会打印3
在ES2022之前,并没有实际意义上的私有字段。大家形成一种默契,通常用下划线_开头的字段名来表示私有字段,但是这些字段还是可以手动更改的。
ES2022给我们提供了更加安全便捷的私有字段定义方法,就是以#开头命名的字段,都会被当成私有字段,在class外部是没办法直接读取、修改这些私有字段的。
class X {#a = 123;b = 2;}const x = new X();x.b; // 2x.#a; // Uncaught SyntaxError: Private field '#a' must be declared in an enclosing class
2.RegExp Match Indices
正则表达式增加了一个/d修饰符,当使用正则表达式的exec()方法时,如果有/d修饰符,那么结果会多返回一个indices属性,用来表示匹配的结果的在原字符串中的起始index值。
const re1 = /a+/d;const s1 = "aaaabbb";const m1 = re1.exec(s1);m1.indices[0] //[0, 3];
如果正则表达式中有具名捕获组,那么indices[1]则表示捕获组的起始index值,indices.groups同样记录了捕获组信息。
const re1 = /a+(?<B>b+)/d;const s1 = "aaabbbccc";const m1 = re1.exec(s1);m1.indices[1] //[3, 6];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],
- 当参数是其它值或者空时,直接返回数组第一个元素
const arr = [1, 2, 3, 4, 5];arr.at(1) // 2arr.at(-1) // 5arr.at(-10) // undefinedarr.at('aaaa') // 1arr.at() // 1
6.Error Cause
之前,我们在封装错误信息时,比较繁琐,没有统一的字段的表示错误原因。
新提案在Error构造函数新增了一个可选参数cause,允许我们在实例化Error时,将错误原因以参数形式传入,省去了我们自己单独处理的成本。
async function doJob() {const rawResource = await fetch('//domain/resource-a').catch(err => {throw new Error('Download raw resource failed', { cause: err });});const jobResult = doComputationalHeavyJob(rawResource);await fetch('//domain/upload', { method: 'POST', body: jobResult }).catch(err => {throw new Error('Upload job result failed', { cause: err });});}try {await doJob();} catch (e) {console.log(e);console.log('Caused by', e.cause);}// Error: Upload job result failed// Caused by TypeError: Failed to fetch
