2022 年 6 月 22 日,第 123 届 ECMA 大会批准了 ECMAScript 2022 语言标准,这意味着它当初正式成为规范。上面就来看看 ECMAScript 2022 有哪些新个性!

新个性总览

  • Top-level Await
  • Object.hasOwn()
  • at()
  • error.cause
  • 正则表达式匹配索引
  • ES14: Array.prototype.findLast 和 Array.prototype.findLastIndex 的提案。

Top-level Await(顶级 await)

async 和 await 在 ES2017(ES8)中引入用来简化 Promise 操作,然而却有一个问题,就是 await 只能在 async 外部应用, 当咱们间接在最外层应用 await 的时候就会报错:
`Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
`

没有顶级 await 之前,当咱们导入一个内部promise.js文件的时候,因为须要期待这个内部 js 执行实现再执行别的操作

// promise.jslet res = { name: "" },  num;const np = () => {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve(456);    }, 100);  });};const p = async () => {  const res1 = await np();  res.name = res1;  num = res1;};p();export default res;//validate.jsimport res from "./p.js";console.log("res", res, num);// 这时 res 和 num 都是 undefined

因为 res 和 num 须要在异步执行实现之后能力拜访它,所以咱们能够加个定时器来解决

setTimeout(() => { console.log("res3000", res, num);}, 1000);// res 能够正确输入 {name: 456}// num 还是 undefined

为什么 res 能够失常输入,而 num 不行?

这是因为 res 时对象,是一个援用类型,当过了 100 毫秒后,异步操作以及执行实现并且赋值了,而导出的res 和 p.js 外面的res指向同一个地址,所以能监听到扭转,然而 num 是根本数据类型,导出的和p.js外面的不是同一个,所以无奈监听到,故而始终是 undefined,而且在理论我的项目中,异步工夫是不确定,所以这种办法存在肯定缺点,这时就能够应用 顶级 await 来实现

// p.jslet res = { name: "" },  num;const np = () => {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve(456);    }, 100);  });};// 这里进行革新const res1 = await np();res.name = res1;num = res1;export { res, num };//validate.jsimport { res, num } from "./p.js";console.log("res adn num", res, num);// 全副失常输入

代码自上而下执行,遇到 await 进入期待,np 函数执行实现之后进行赋值,赋值实现后导出。

await 应用局部场景

  • 资源初始化:例如,期待某个文件(图片、js(初始化变量的js)等)加载实现之后再渲染
  • 依赖回退:
let depVersion;try {  depVersion = await import(xxx/depVersion-2.0.0.min.js)}catch {  depVersion = await import(xxx/depVersion-1.5.0.min.js)}
  • 模块动静加载:
let myModule = 'await-module'const module = await import(`./${myModule}`)
  • 兼容性:

Object.hasOwn()

ES5:当咱们查看一个属性时候属于对象的时候能够应用

罕用例子:

object = {firstName: '四', lastName: '李'}for (const key in object) {  if (Object.hasOwnProperty.call(object, key)) {    const element = object[key];    console.log(element)  }}

ES6:Object.hasOwn 个性是一种更简洁、更牢靠的查看属性是否间接设置在对象上的办法

罕用例子:

object = {firstName: '四', lastName: '李'}for (const key in object) {  if (Object.hasOwn(object, key)) {    const element = object[key];    console.log(element)  }}

at()

一个 TC39 提案,向所有根本可索引类(Array、String、TypedArray)增加 .at() 办法

ES13 之前,要从可索引对象的开端拜访值,通常的做法是写入 arr[arr.length - N] 或者应用 arr.slice(-N)[0]

ES13:能够应用 at() 办法

// 数组const array = [0,1,2,3,4,5];array.at(-1) // 5array.at(-2) // 4// 字符串string= 'abcdefg'string.at(-2) // f

Error Cause

有时,对于代码块的谬误须要依据其起因进行不同的解决,但谬误的起因又较为类似(例如:谬误的类型和音讯均雷同)。

// ES13 之前通常用以下几种形式处理错误async function errFunc() {  const rawResource = await axios('/testError')    .catch(err => {      // 第一种      throw new Error('我的错误信息:', err.message);      // 第二种,须要连贯错误信息      const wrapErr = new Error('Download raw resource failed');      //    本人创立 一个 cause 属性来接管谬误上下文      wrapErr.cause = '谬误起因:' + err;      throw wrapErr;      // 第三种,须要连贯错误信息      class CustomError extends Error {         constructor(msg, cause) {           super(msg);            //    本人创立 一个 cause 属性来接管谬误上下文           this.cause = cause;         }       }       throw new CustomError('Download raw resource failed', err);    });}try {    const res = await errFunc()}catch (err) {    console.log(err)    console.log(err.cause)}// 第一种输入:Uncaught Error: 我的错误信息:Failed to fetch// 第一种输入:undefined// 第二种输入:Uncaught Error: 我的错误信息 // 第二种输入:谬误起因: err // 第三种:Uncaught Error: 我的错误信息// 第三种输入:谬误起因: err 

正则表达式匹配索引

给正则表达式增加修饰符 d,会生成匹配对象,记录每个组捕捉的开始和完结索引,因为 /d 标识的存在,m1 还有一个属性 .indices,它用来记录捕捉的每个编号组

// ?<m>n:命名分组,m 为组名称,n 为正则表达式const re1 = /a+(?<Z>z)?/d;// indices are relative to start of the input string:const s1 = "xaaaz";const m1 = re1.exec(s1);console.log(m1.indices)

在做字符串切割时,能够通过修饰符 d 匹配出索引范畴从而进行字符切割

// 应用s1.slice(...m1.indices[0]) // aaaz// 相当于s1.slice(1, 5)  // aaaz// 按组切割s1.slice(...m1.indices.groups['Z']) // z

类 class

公共实例字段

在 ES13 之前,在定义类的属性时,须要在构造函数中定义了实例字段和绑定办法

class myClass {  constructor() {    this.count = 1    this.increment = this.increment.bind(this);  }  increment() {    this.count += 1  }}

ES 13 能够应用公共实例字段,这样就简化了类的定义,使代码更加简洁、可读

class myClass {  count = 1  increment = () => {    this.count += 1  }}

公有实例字段

默认状况下,class 中所有属性都是公共的,能够在 class 之外进行批改,例如

class myClass {  count = 1  setCount = () => {    this.count += 1  }}const es13 = new myClass()es13.count = 5// myClass {count: 5, setCount: ƒ}count: 5setCount: () => {     this.count += 1   }[[Prototype]]: Object

通过下面的例子能够看到,当咱们间接设置 count 属性的时候,是间接跳过 setCount 进行设置的,有时候咱们并不想这样,所以能够应用公有实例字段,用法很简略,只须要在公有字段增加 # 就能够实现,当然了,在调用的时候咱们也应该加上 # 进行调用,如下:

class myClass {  #count = 1  setCount = () => {    this.#count += 1  }}const es13 = new myClass()es13.setCount() // 失常批改,每执行执行一次 setCount 办法后 #count的值每一次都加1// 间接批改公有属性es13.#count = 5// 报错:Uncaught SyntaxError: Private field '#count' must be declared in an enclosing class

能够看到,当咱们间接批改公有属性之后,浏览器间接抛出谬误:Uncaught SyntaxError: Private field '#count' must be declared in an enclosing class

公有办法

都有公有属性了,怎么能少了公有办法呢,办法和属性一下只有加上 # 即可:

class myClass {  #count = 1  #setCount = () => {    this.#count += 1  }    newSetCount = () => {    this.#setCount()  }}const es13 = new myClass()es13.#setCount() // 间接调用公有办法报错:Uncaught SyntaxError: Private field '#setCount' must be declared in an enclosing class//通过公共办法 newSetCount 调用es13.newSetCount() // VM436:9 Uncaught TypeError: Cannot read private member #setCount from an object whose class did not declare it

动态公共字段、动态公有字段、动态公有办法

与公有实例字段和办法一样,动态公有字段和办法也应用哈希#前缀来定义

class myClass { //动态公共字段 static color = 'blue' // 动态公有字段 static #count = 1 // 动态公有办法 static #setCount = () => {    this.#count += 1  }  newSetCount = () => {    this.#setCount()  }}const es13 = new myClass()实例 es13 下面只有 newSetCount() 办法es13.newSetCount() // 报错:Uncaught SyntaxError: Private field '#setCount' must be declared in an enclosing class

公有动态字段有一个限度:只有定义公有动态字段的类能力拜访该字段。这可能在应用 this 时导致出其不意的状况, 所有咱们须要改一下

class myClass {// 动态公有字段 static #count = 1 // 动态公有办法 static #setCount = () => {   // 实例化之后,this 不再指向 myClass,所有须要改成 myClass 类调用    myClass.#count += 1  }  newSetCount = () => {    // 实例化之后,this 不再指向 myClass,所有须要改成 myClass 类调用    myClass.#setCount()  }}const es13 = new myClass()es13.newSetCount() // 胜利

类动态块

在以前,如果咱们心愿在初始化期间像 try…catch 一样进行异样解决,就不得不在类之外编写此逻辑。该标准就提供了一种在类申明/定义期间评估动态初始化代码块的优雅办法,能够拜访类的公有字段。

ES13之前

class Person {    static EEEOR = "error"    static SUCCESS_TYPE = "success_type";    constructor() {        // ...    }    try {        // ...    } catch {        // ...    }}

下面代码间接报错:Uncaught SyntaxError: Unexpected token '{'

ES13 : 间接将 try...cathc 应用 static 包裹起来即可

class Person {    static EEEOR = "error"    static SUCCESS_TYPE = "success_type";    constructor() {        // ...    }    static {      try {        // ...      } catch {        // ...      }    }}

ES14 新提案

  • Array.prototype.findLast
  • Array.prototype.findLastIndex

Tips:

  • Array.prototype.findLastArray.prototype.find 的行为雷同,但会从最初一个迭代到第一个。
  • Array.prototype.findLastIndexArray.prototype.findIndex的行为雷同,但会从最初一个迭代到第一个。
const array = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }];array.find(n => n.value % 2 === 1); // { value: 1 }array.findIndex(n => n.value % 2 === 1); // 0// ======== Before the proposal =========== // find[...array].reverse().find(n => n.value % 2 === 1); // { value: 3 }// findIndexarray.length - 1 - [...array].reverse().findIndex(n => n.value % 2 === 1); // 2array.length - 1 - [...array].reverse().findIndex(n => n.value === 42); // should be -1, but 4// ======== In the proposal =========== // findarray.findLast(n => n.value % 2 === 1); // { value: 3 }// findIndexarray.findLastIndex(n => n.value % 2 === 1); // 2array.findLastIndex(n => n.value === 42); // -1

原文链接:ECMAScript 2022(ES13)初体验