ES2022尝个鲜

133 阅读6分钟
1、顶层-await

proposal-top-level-await

es2022之前,await 只能在 async 内部使用,否则报错

  <script>
    function testAwait() {
     console.log(1111)
    }
    await testAwait() // Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
  </script>

2022 开始,可以直接使用,不会报错

  <script>
    function testAwait() {
     console.log(1111)
    }
    await testAwait() // 1111
  </script>
2、数组的实例方法: at

proposal-relative-indexing-method

出现的原因: JavaScript 不支持数组的负索引,如果要引用数组的最后一个成员,不能写成arr[-1],只能使用arr[arr.length - 1]

为了解决这个问题,ES2022 为数组实例增加了at()方法,接受一个整数作为参数,返回对应位置的成员,并支持负索引。这个方法不仅可用于数组,也可用于字符串和类型数组(TypedArray)。 ps: 如果参数位置超出了数组范围,at()返回undefined

  • 数组使用:
const arr = [5, 12, 8, 130, 44];
arr.at(2) // 8
arr.at(-2) // 130
arr.at(6) // undefined
  • 字符串和 TypedArray 对象使用at() 方法
const str = 'test at';
console.log(str.at(-1)); // t
console.log(str.at(-2)); // a
const typedArray = new Uint8Array([1,2,3,4]);
console.log(typedArray.at(-1)); // 4
console.log(typedArray.at(-2)); // 3

3、Object-hasOwn

proposal-accessible-object-hasownproperty

JavaScript 对象的属性分成两种:自身的属性和继承的属性。对象实例有一个hasOwnProperty()方法,可以判断某个属性是否为原生属性。ES2022 在Object对象上面新增了一个静态方法Object.hasOwn(),也可以判断是否为自身的属性

Object.hasOwn()可以接受两个参数,第一个是所要判断的对象,第二个是属性名。

const obj = Object.create({ a: 123 });
obj.b = 456;

console.log(Object.hasOwn(obj, 'a')) // false
console.log(Object.hasOwn(obj, 'b')) // true

console.log(obj.hasOwnProperty('a'))  // false
console.log(obj.hasOwnProperty('b'))  // true

上面示例中,对象obj的属性a是继承属性,属性b原生属性Object.hasOwn()对属性a返回false,对属性b返回true

Object.hasOwn()的一个好处是,对于不继承Object.prototype的对象不会报错,而hasOwnProperty()是会报错的。

const obj = Object.create(null);

console.log(obj.hasOwnProperty(o'a')) // 报错
console.log(Object.hasOwn(obj, 'foo')) // false

上面示例中,Object.create(null)返回的对象obj是没有原型的,不继承任何属性,这导致调用obj.hasOwnProperty()会报错,但是Object.hasOwn()就能正确处理这种情况。

4、Error 对象的 cause 属性

proposal-error-cause

Error 对象用来表示代码运行时的异常情况,但是从这个对象拿到的上下文信息,有时很难解读,也不够充分。ES2022Error 对象添加了一个cause属性,可以在生成错误时,添加报错原因的描述

用法:

const testCause = new Error('an error!', { cause: 'Error cause' });
testCause.cause; // 'Error cause'

casue属性可以放置任意内容,不必一定是字符串,可以是对象等

const testCause = new Error('an error!', { cause: {
  errorMsg: 'Error cause'
} });
testCause.cause; // { errorMsg: 'Error cause'}

5、数组的findLast、findLastIndex

proposal-array-find-from-last

es2022之前我们可以使用find() findIndex() 方法查找数组中的符合的 元素和下标, 他们都是一个短路操作,找到后就不继续往下直接,直接退出

数组实例的find()方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined

数组实例的findIndex()方法的用法与find()方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

find()findIndex()都是从数组的0号位,依次向后检查,正向查找

ES2022增加的findLast()findLastIndex() 从数组的最后一个成员开始,依次往前查找,其他的和find()findIndex()保持一致

使用:

const array = [
  { value: 1 },
  { value: 2 },
  { value: 3 },
  { value: 4 }
];
const lastObj =  array.findLast(n => n.value % 2 === 1);
const lastIndex = array.findLastIndex(n => n.value % 2 === 1);
console.log(lastObj)  // { value: 3 }
console.log(lastIndex)  // 2
6、正则的 d 修饰符:正则匹配索引

proposal-regexp-match-Indices

组匹配的结果,在原始字符串里面的开始位置和结束位置,目前获取并不是很方便。正则实例的exec()方法有一个index属性,可以获取整个匹配结果的开始位置。但是,组匹配的每个组的开始位置,很难拿到。

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

设置 d 标志后,返回的对象将具有包含开始和结束索引的 indices 属性。

onst text = 'zabbcdef';
const re = /ab/d;
const result = re.exec(text);

result.index // 1
result.indices // [ [1, 3] ]

regexp.jpg

7、Class 类 实例属性的新写法

proposal-class-fields 实例属性现在除了可以定义在constructor()方法里面的this上面,也可以定义在类内部的最顶层。 这种新写法的好处是,所有实例对象自身的属性都定义在类的头部,看上去比较整齐,一眼就能看出这个类有哪些实例属性

class Person {
 name = 'test' // 写在外层
 constructor() {
   this.age = 16
 }
}

注意,新写法定义的属性是实例对象自身的属性,而不是定义在实例对象的原型上面。

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

proposal-class-fields

  • 早期解决方案

私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问,早期未实现都通过伪代码来处理

class Widget {
  // 公有方法
  foo (baz) {
    this._bar(baz);
  }

  // 私有方法
  _bar(baz) {
    return this.snaf = baz;
  }

  // ...
}

  • es2022正式使用

私有属性,方法是在属性名之前使用#表示

class Foo {
  // 私有属性
  #a;
  #b;
  constructor(a, b) {
    this.#a = a;
    this.#b = b;
  }
  // 私有方法
  #sum() {
    return this.#a + this.#b;
  }
  printSum() {
    console.log(this.#sum());
  }
}

在类的外部,读取或写入私有属性,都会报错。

9、Class in 运算符

proposal-private-fields-in-in 直接访问某个类不存在的私有属性会报错,但是访问不存在的公开属性不会报错。这个特性可以用来判断,某个对象是否为类的实例

class C {
  #brand;
  static isC(obj) {
    if (#brand in obj) {
      // 私有属性 #brand 存在
      return true;
    } else {
      // 私有属性 #foo 不存在
      return false;
    }
  }
}
10、Class 静态属性

proposal-class-fields

静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。 写法是在实例属性的前面,加上static关键字

// 老写法
class Foo {
  // ...
}
Foo.prop = 1;

// 新写法
class Foo {
  static prop = 1;
}

11、Class 静态块

proposal-class-static-block

作用:允许在类的内部设置一个代码块,在类生成时运行一次,主要作用是: 1、对静态属性进行初始化, 2、将私有属性与类的外部代码分享

let getX;
class C {
  static x = 10;
  static y;
  static z;
   #x = 1;
   // 静态块只执行一次
  static {
    getX = obj => obj.#x; // 外部的getX方法获取 私有属性
    try {
      const obj = doSomethingWith(this.x);
      this.y = obj.y;
      this.z = obj.z;
    }
    catch {
      this.y = ...;
      this.z = ...;
    }
  }
}

上面代码中,类的内部有一个 static 代码块,这就是静态块。它的好处是将静态属性y和z的初始化逻辑,写入了类的内部,而且只运行一次