一文搞懂ES2022🚀

2,023 阅读4分钟

ECMAScript 2022 (ES13) 发布也有段时间了,平时工作中也会用到一些,总结了一下新特性😎,大致如下:

  1. at()
  2. Top-level await
  3. Object.hasOwn()
  4. findLast和findLastIndex
  5. RegExp匹配索引
  6. Error的 cause 属性
  7. Class类 声明
  8. Class类 私有方法和私有属性
  9. Class类 静态字段和方法
  10. Class类 静态初始化块
  11. Class类 私有字段检查

1. at()

这是平时工作中用到多的方法,当给出负整数索引时,就会从数组的最后一项开始检索。以前我们引用数组最后一个元素一般用的是arr[arr.length - 1], 现在我们可以用arr.at(-1)来代替了。

🚀 ES2022之前

const arr = [1, 2, 3, 4]
console.log(arr[arr.length - 1]) // 4

🚀 ES2022之后

const arr = [1, 2, 3, 4]
console.log(arr.at(-1)) // 4

// 字符串和TypedArray(类型数组)也可以使用at(), 举个🌰
const str = "zhangSan"
console.log(str.at(-3)) // S
const typedArray = new Int8Array([1, 2, 3, 4, 5, 6])
console.log(typedArray.at(-2)) // 5

2. Top-level await

在ES2022之前,我们只能在async函数内部使用 await。但是现在,await 提升到模块中,不需要和 async 强绑定了。

🚀 ES2022之前

await Promise.resolve(console.log('zhangsan'))
// 输出 Uncaught SyntaxError: await is only valid in async function
// 解决方法
(async function() {
  await Promise.resolve(console.log('zhangsan'))
  // 输出 zhangsan
}());

🚀 ES2022之后

await Promise.resolve(console.log('zhangsan'))
// 输出: zhangsan

3. Object.hasOwn()

可以理解为是对hasOwnProperty的简化,看下面例子:

🚀 ES2022之前

for (let k in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, 'key')) {
    // ...
  }
}

🚀 ES2022之后

for (let k in obj) {
  if (Object.hasOwn(obj, 'key')) {
    // ...
  }
}

4. findLast和findLastIndex

在ES2022之前我们通过findfindIndex查找数组元素和下标,它是从第一个开始查找,查找到元素后返回。findLastfindLastIndex是从最后一个开始查找,查找到之后返回。

🚀 ES2022之前

// 查找数组第一个出现的奇数
const arr = [16, 11, 22, 18, 7, 15, 12, 13]
console.log(arr.find(t => t % 2 === 1)) // 11
console.log(arr.findIndex(t => t % 2 === 1)) // 1

🚀 ES2022之后

// 查找数组最后一个出现的奇数
const arr = [16, 11, 22, 18, 7, 15, 12, 13];
console.log(arr.findLast(t => t % 2 === 1)) // 13
console.log(arr.findLastIndex(t => t % 2 === 1)) // 7

5. RegExp匹配索引

ES2022新增了d修饰符,这个修饰符可以让exec()、match()的返回结果添加indices属性,该属性包含匹配的开始位置和结束位置

🚀 ES2022之前

const t = 'abcdefghijk'
const n = /def/
const r = n.exec(t)
console.log(r[0]) // def
console.log(r.index) // 3

🚀 ES2022之后

const t = 'abcdefghijk'
const n = /def/d
const r = n.exec(t)
console.log(r[0]) // def
console.log(r.index) // 3
console.log(r.indices[0]) // [3, 6]

6. Error的 cause 属性

🚀 ES2022之前 这是由阿里程序员提出的提案。ES2022为 Error 对象添加了一个cause属性,可以在生成错误时,添加报错原因的描述

async function getPerson(url) {
  try {
    const [res] = await fetch(url)
  } catch(e) {
    throw new Error(e)
  }
}

getPerson('test');
// Uncaught Error: TypeError: (intermediate value) is not iterable

🚀 ES2022之后

async function getPerson(url) {
  try {
    const [res] = await fetch(url)
  } catch(e) {
    throw new Error('error', { cause: e })
  }
}

try {
  await getPerson('test')
} catch(e) {
  console.error(e)
  console.error(e.cause)
  // Error: error
  // TypeError: (intermediate value) is not iterable
}

7. Class类 声明

在ES2022之前,类字段只能在其构造函数中声明。但是现在可以在类的最外层范围内声明或定义它们

🚀 ES2022之前

class Person {
  constructor() {
    this.name = 'zhangsan'
    this.age = 10
  }
}
const person = new Person()
console.log(person.name) // zhangsan

🚀 ES2022之后

class Person {
  name = 'zhangsan'
  age = 10;
}
const person = new Person()
console.log(person.name) // zhangsan

8. Class类 私有方法和私有属性

以前我们声明私有方法或字段时,一般是在方法名开头加下划线_,但这并不能保持完全私有,所以ES2022添加了新属性#来定义私有方法和私有属性。我们只需要将#添加在方法名称的开头,这样将被声明为私有。

🚀 ES2022之前

class Person {
  _name = 'zhangsan'
  _getName() {
    console.log(this._name)
  }
}
const person = new Person()
console.log(person._name) // zhangsan
console.log(person._getName()) // zhangsan

🚀 ES2022之后

class Person {
  #name = 'zhangsan'
  #getName() {
    console.log(this._name)
  }
}
const person = new Person()
console.log(person.#name);
// 输出 Uncaught SyntaxError: Private field '#name' must be declared in an enclosing class
console.log(person.#getName())
// 输出 Uncaught SyntaxError: Private field '#getName' must be declared in an enclosing class

9. Class类 静态字段和方法

我们可以往类添加静态字段和方法,并且直接访问

🚀 ES2022之前

// 老写法
class Person {
  name = 'zhangsan'
}
console.log(Person.name) // undefined

🚀 ES2022之后

class Person {
  static name = 'zhangsan'
  static getPerson() {
    return this.name
  }
}
console.log(Person.name) // zhangsan
console.log(Person.getPerson()) // zhangsan

10. Class类 静态初始化块

允许在类的内部设置一个代码块,在类生成时运行一次,很像静态的 constructor,主要是对静态属性进行初始化,并且可以将私有属性暴露出去。

let getPersonName

class Person {
  static #name
  static #age

  static getPersonInfo() {
    return `${this.#name}${this.#age}`
  }

  static {
    this.#name = 'zhangsan'
    this.#age = 18
    
    getPersonName = () => {
      return this.#name
    }
  }
}

console.log(Person.getPersonInfo()) // zhangsan:18
// 访问私有变量
console.log(getPersonName()) // zhangsan

11. Class类 私有字段检查

这个特性可以用来判断某个对象是否为类的实例,还能用来判断对象或实例是否存在私有字段或方法

class Person {
  #name
  hasName() {
    return #name in this
  }
  
  static isPerson(obj) {
    return #name in obj
  }
}

const person = new Person()
console.log(person.hasName()) // true
console.log(Person.isPerson(person)) // true
console.log(Person.isPerson({})) // false