ECMA2022 - ES13 新特性

576 阅读7分钟

一、前言

😆 Hi,大家好,我是张玥卿云,一个面向未来编程的程序员!欢迎小伙伴们和我一起学习进步!
ECMA2022 (ES13) 已经是 ECMAScript 语言的第 13 个版本啦!🥰我们来看看这个版本为我们带来了哪些新特性吧!

二、概览

ES13 为我们带来了 6 个新特性:

  1. 模块顶层作用域支持 await 表达式。
  2. 新增私有类元素、静态块;in 操作符支持私有类元素。
  3. 正则新增 d 标志和其对应的 hasIndices 属性,提供了获取捕获组开始索引和结束索引的方法。
  4. Error 实例增加 cause 属性,可携带更多错误信息。
  5. Strings、Arrays、TypedArrays 新增 at 方法,支持关联访问。
  6. Object.hasOwn 代替 Object.prototype.hasOwnProperty,判断对象是否含有属性。

接下来的内容将详细介绍每个新特性。

三、顶层 await 表达式

以往我们总是在异步函数体内使用 await 表达式,自 ES13 后,我们也可以在一个模块的顶层使用它了。

在模块顶层使用 await 表达式

// 异步加载资源
import { fetchPerson } from '@/services/person';
const person = await fetchPerson();

// 异步加载组件
await import('your-component-path'); 

在异步函数中使用 await 表达式

import { get } from '@/utils/request';

export async function getPerson() {
    const person = await get('/person');
    return person;
}

错误用法

在以下几种语句内的 Formal Parameters 中使用 Await 表达式,会引发静态句法的语义错误。

  1. 异步函数声明 (AsyncFunctionDeclaration)
  2. 异步函数表达式 (AsyncFunctionExpression)
  3. 异步生成器函数表达式 (AsyncGeneratorExpression)
  4. Await 表达式内部 (AwaitExpression)

特殊情况

在早期,await 没有出现在关键字中,为了兼容旧代码,在一些特殊的 await 作为参数出现的情况下,它会被解释为标识符。如下所述:

  1. 当 await 出现在 AsyncFunctionBody 和 AsyncFunctionDeclaration、AsyncFunctionExpression、AsyncGeneratorDeclaration、AsyncGeneratorExpression 的 FormalParameter 外部时,await 会被解析为标识符。
  2. 当 await 出现在 FunctionExpression, GeneratorExpression, AsyncGeneratorExpression 的 BindingIdentifier 中时,await 会被解析为标识符。

四、class 新特性

4.1 私有类元素

在类的定义中,以 "#" 开头的标识符为私有标识符,由私有标识符定义的类元素被称为私有类元素,私有类元素只能在类中才能被访问到。类的属性、静态属性、方法、静态方法、访问器、静态访问器都可以被定义为私有类元素。

class ClassA {
    // 私有属性
    #privateProperty;

    // 静态私有属性
    static #privateStaticProperty;

    // 静态私有 Getter
    static get #privateStaticGet() {
        return 'private-static-get';
    }

    // 静态私有 Setter
    static set #privateStaticSet(val) {
    }

    // 静态私有方法
    static #privateStaticMethod() {
        return 'private-static-method'
    }

    constructor(propertyValue) {
        // 初始化私有属性
        this.#privateProperty = propertyValue;
    }

    // 私有 Get
    get #privateGet() {
        return 'private-get'
    }

    // 私有 Set
    set #privateSet() {
    }

    // 私有方法
    #privateMethod() {
        return 'private-method'
    }
} 

在类的内部可以正常访问私有类元素,在类的外部访问私有类元素会抛出句法错误。

class ClassA {
    // 私有属性
    #privateProperty;

    constructor(property, privateProperty) {
        this.property = property;
        this.#privateProperty = privateProperty;
    }

    // 在方法中访问私有属性
    getPrivateProperty() {
        return this.#privateProperty;
    }
}

const instance = new ClassA('property', 'private-property');

instance.property; // 'property'
instance.#privateProperty; // Uncaught SyntaxError: Private field '#privateProperty' must be declared in an enclosing class
instance.getPrivateProperty(); // 'private-property'

以上就是私有类元素的用法,它有效隔离了类内外的数据和逻辑,进一步增强了封装的效果,使程序更加健壮。

4.2 静态块

静态块为我们提供了更加灵活的静态类元素初始化渠道,我们可以在静态块中使用一系列的语句来完成静态类元素的初始化。我们可以利用 this 在静态块中访问类的其他静态属性(包括私有属性)。

class ClassA {
    // 静态属性
    static staticProperty;

    // 静态块初始化静态属性,捕捉错误
    static {
        try {
            this.staticProperty = getStaticProperty();
        } catch {
            console.log('Error');
        }
    }
}

当一个类具有多个静态块时,它们会按照定义的顺序进行执行。

class ClassA {
    // 静态属性 A
    static staticPropertyA;

    // 静态块 A
    static {
        this.staticPropertyA = 'static-block-a';
        console.log('static-block-a');
    }

    // 静态属性 B
    static staticPropertyB;

    // 静态块 B
    static {
        this.staticPropertyB - 'static-block-b';
        console.log('static-block-b');
    }
}

// 输出
// static-block-a
// static-block-b

当一个类具有父类时,会先执行父类的静态块,再执行子类的静态块。我们可以利用 super 在子类的静态块中访问父类的属性。

// 父类
class ParentClass {
    // 父类属性
    static parentProperty;

    // 父类静态块
    static {
        this.parentProperty = 'parent-property';
        console.log('parent-static-block');
    }
}

// 子类
class ChildClass extends ParentClass {
    // 子类静态块
    static {
        console.log(super.parentProperty);
        console.log('child-static-block');
    }
}

// 输出
// parent-static-block
// parent-property
// child-static-block

4.3 私有 in 操作符

我们知道 in 操作符可以帮我们判断实例中是否存在属性,当新增了私有化类元素后,我们也可以和下面例子一样,在类定义内使用 in 操作符判断私有化类元素存在与否。

class ClassA {
    // 私有属性
    #privateProperty;

    // 利用 in 操作符判断私有属性是否存在
    static hasPrivateProperty(instance) {
        return #privateProperty in instance
    }

    constructor(privateProperty) {
        this.#privateProperty = privateProperty;
    }
}

const instance = new ClassA('private-property');
ClassA.hasPrivateProperty(instance);

// 输出
// true

小知识 “私有类元素标准推导”

下面我们来看看标准中是如何表达私有化属性的把~

标准中定义了私有标识符,它由 "#" 开头,后接普通标识符。

PrivateIdentifier::
    # IdentifierName

在类元素名中,包含了私有标识符,所以具有类元素名的类元素都可以被定义为私有类元素。

ClassElementName:
    PropertyName
    PrivateIdentifier

在类元素中又包含了方法、静态方法、属性、静态属性、类静态块,除了静态块没有类元素名外,其他都可被定义为私有类元素。

ClassElement:
    MethodDefination
    static MethodDefination
    FieldDefination
    static FieldDefination
    ClassStaticBlock

方法的定义包含了类方法定义表达式、生成器方法、异步方法、异步生成器方法、 get 访问器、set 访问器。这些也都可以被定义为私有类元素。

MethodDefination: 
    ClassElementName (UniqueFormalParameters) { FunctionBody }
    GeneratorMethod
    AsyncMethod
    AsyncGeneratorMethod
    get ClassElementName 
    set ClassElementName

根据以上标准定义的推导,类属性、方法、访问器,静态类属性、方法、访问器都可以通过私有标识符定义为私有类元素。

五、正则 /d 标志

我们常用正则表达式来处理字符串,正则表达式有很多标志,它决定了正则状态机的行为和输出结果。ES13 新增的 d 标志对应正则实例的 hasIndices 属性,当设置 d 标志时,hasIndices 为 true 。使用 d 标志后,正则表达式的匹配结果将包含每个捕获组捕获子字符串的开始和结束游标。

// 字符串
const str = "today is saturday";

// 正则表达式
const reg = /saturday/d;

// 匹配结果输出游标
const [start, end] = reg.exec(str).indices[0];

console.log([start, end]); // [9, 17]

六、Error 对象的 cause 属性

在以往 Error 对象只能传递消息信息,现在 ES13 为 Error 增添了 cause 属性,它可以是任意数据类型,方便我们获取更多地错误信息。

try {
    // 抛出带 cause 属性的 Error实例
    throw new Error('faied message', { cause: 'cause' });
} catch (error) {
    // 捕获 error 并输出 cause
    console.log(error.cause)
}

// 输出
// cause

七、Strings、Arrays、TypedArrays 的 at 方法

我们利用下标访问数组元素时,下标会被转换为字符串,负数下标也对应着一个独立的数组元素,所以 Js 的数组是不支持关联访问的。ES13 新增了 at 方法,使得我们可以利用负数索引进行关联访问,例如以下示例,我们可以利用 at 方法和负数索引 -2 来访问倒数第二个元素。

const array = [5, 12, 8, 130, 44];

array.at[-2]; // 130

八、Object.hasOwn

ES13 新增了 Object.hasOwn 方法判断这个实例上是否有属性,以代替之前的 Object.prototype.hasOwnProperty 方法。

const object = {
    count: 1
};

Object.hasOwn(object, 'count'); // true
Object.hasOwn(object, 'toString'); // false
Object.hasOwn(object, 'property'); // false

九、结尾

这些就是 ES13 中所有的新特性啦! 如有错误,欢迎小伙伴们一起讨论~ @V@ ~

最后来则广告 @v@~

✨ 布灵布灵!YQY 低代码平台首发啦!

🍓 基本功能

  • 通过拖拽自动生成 React 项目代码(包含路由、布局、页面、组件、css样式)。
  • 自动化生成代码仓库。
  • 自动化部署。
  • 快捷访问部署的项目、页面。
  • 通过低代码平台对已生成的项目进行修改。
  • 拉取项目至本地,由开发人员手动开发,推送到远程仓库后自动化部署。
  • 接入不同组件库。
  • 支持接入埋点、监控等前端架构。

🍓 优点

  • 生成的代码可读性好,包含注释。
  • 可生成不同类型的组件(函数组件、类组件)。
  • 可自动生成项目、布局、页面、路由等。
  • 支持自动创建代码仓库、自动化部署。
  • 支持接入不同组件库。
  • 支持接入埋点、监控等企业级前端架构。

😈 如感兴趣,可联系本人:张玥卿云

🐼 其他

© copy-rigyt:zhangyueqingyun