E

ES2022 的所有新功能

2025-06-08

ES2022 的所有新功能

本文最初发布在我的博客上。更多文章和教程,请访问inspiredwebdev.com。查看我Educative上的JavaScript 课程,学习从基础知识到 ES2022 的所有内容。

 

自 2015 年以来,每年JavaScript都会不断更新其规格并添加新的有趣功能。

在本文中,我们将了解即将发生的事情,因为许多功能已经达到第 4 阶段并将包含在规范中。

对于那些不知道的人来说,提案过程分为 4 个阶段,其中第 4 个阶段是最后一个阶段,标志着提案完成。

作为开发者,及时了解语言的最新规范至关重要。如果你觉得自己跟不上JavaScript过去几年的诸多更新,我推荐你阅读我的书,它涵盖了从语言基础知识到最新的 ES2022 规范的所有内容,甚至还包含一些简介。你可以在GithubTypeScript上免费阅读,那里还有购买电子书的链接,或者你也可以在Educative上查看我的课程。

现在,让我们开始了解 ES2022 的第一个新功能:

类字段

类公共实例字段和私有实例字段

在 ES2022 之前,我们会像这样定义 a 的class属性constructor

class ButtonToggle extends HTMLElement {
    constructor(){
        super();
        // public field
        this.color = 'green'
        // private field
        this._value = true;
    }

    toggle(){
        this.value = !this.value
    }
}

const button = new ButtonToggle();
console.log(button.color);
// green - public fields are accessible from outside classes

button._value = false;
console.log(button._value);
// false - no error thrown, we can access it from outside the class
Enter fullscreen mode Exit fullscreen mode

在 中constructor,我们定义了两个字段。如您所见,其中一个字段的_名称前面带有 ,这只是一种JavaScript命名约定,用于声明该字段private只能在方法内部访问class。当然,这只是一种命名约定,而不是语言本身强制要求的,这就是为什么当我们尝试访问它时没有引发任何错误。

在 ES2022 中,我们有一种更简单的方法来声明publicprivate字段。让我们看一下这个更新的示例:

class ButtonToggle extends HTMLElement {

    color = 'green';
    #value = true;

    toggle(){
        this.#value = !this.#value;
    }
}
const button = new ButtonToggle();
console.log(button.color);
// green - public fields are accessible from outside classes

// SyntaxError - cannot be accessed or modified from outside the class
console.log(button.#value); 
button.#value = false;
Enter fullscreen mode Exit fullscreen mode

首先要注意的是,不必在 内部定义它们constructor。其次,我们还可以通过在字段名称private前添加前缀来定义字段。#

与前面的例子的主要区别在于,如果我们尝试访问或修改类外的字段,这次将会引发实际错误。

 

JavaScript 类的私有方法和 getter/setter

与前面的例子类似,我们也可以private为我们的类定义方法和 getter/setter。

class ButtonToggle extends HTMLElement {

    color = 'green'
    #value = true;

    #toggle(){
        this.#value = !this.#value
    }

    set #setFalseValue(){
        this.#value = false;
    }
}
const button = new ButtonToggle();
// SyntaxError - cannot be accessed or modified from outside the class
button.#toggle();
// SyntaxError - cannot be accessed or modified from outside the class
button.#setFalseValue;
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们toggle()用替换了#toggle(),从而使toggle方法private只能从 内部访问class

静态类字段和私有静态方法

字段static或方法只能在原型中访问,而不是在每个实例中访问,并且 ES2022 为我们提供了使用关键字定义字段和公共/私有方法的class方法staticstaticstatic

以前我们必须在class身体之外定义它们,例如:

class ButtonToggle extends HTMLElement {
    // ... class body
}
ButtonToggle.toggle(){
    // static method define outside of the class body
}
Enter fullscreen mode Exit fullscreen mode

现在,我们可以class使用static关键字直接在主体内部定义它们:

class ButtonToggle extends HTMLElement {

    #value = true;

    static toggle(){
        this.#value = !this.#value
    }
}
// this will work
ButtonToggle.toggle();

// SyntaxError - private static field
const button = new ButtonToggle();
button.toggle();
Enter fullscreen mode Exit fullscreen mode

正如您在上面的示例中看到的,我们可以toggle()直接访问ButtonToggle,但不能在它的新实例上执行相同的操作。

我们可以static在字段和方法(私有和公共)前面使用关键字,并将其与#private)结合使用,我们可以创建private static只能从原型内部访问的方法class

class ButtonToggle extends HTMLElement {

    #value = true;

    static #toggle(){
        this.#value = !this.#value
    }
}
// this will error, it's a private static method
ButtonToggle.#toggle();
Enter fullscreen mode Exit fullscreen mode

 

符合人体工程学的品牌检查私人领域

正如我们在上面的例子中所看到的,如果我们尝试访问private外部的字段,class它将引发异常,并且不会undefined像字段那样返回public

我们可以尝试使用一个简单的try/catch内部class来检查该字段是否存在:

class ButtonToggle extends HTMLElement {

   // initialised as null
    #value = null;

    get #getValue(){
        if(!this.#value){
            throw new Error('no value');
        } 
        return this.#value
    }

    static isButtonToggle(obj){
        try {
            obj.#getValue;
            return true;
        } catch {
            // could be an error internal to the getter
            return false; 
        }
    }

}
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们添加了一个private getter,如果还没有值,它会抛出一个错误。然后,我们创建了一个static方法来访问它getter,并尝试通过检查 来判断它是否存在try/catch。问题在于,我们不知道 中的代码是catch因为 不存在而执行getter的,还是仅仅因为它抛出了错误。

classES2022 为我们提供了一种简单的方法,通过使用运算符 来检查所述字段是否属于 a in。让我们重新编写示例代码:

class ButtonToggle extends HTMLElement {

   // initialised as null
    value = null;

    get #getValue(){
        if(!this.#value){
            throw new Error('no value');
        } 
        return this.#value;
    }

    static isButtonToggle(obj){
       return #value in obj && #getValue in obj
    }

}
Enter fullscreen mode Exit fullscreen mode

我们的方法isButtonToggle将检查是否class包含private字段“value”和“getValue”。

 

类静态块

这是 ES2022 对字段的又一次升级,static允许我们static在类内部使用块。它试图解决的问题在于,我们无法try/catch在初始化期间执行诸如 a 之类的语句,这意味着我们必须将该代码放在主体之外class

class ButtonToggle{
    value = false;

    get getValue(){
        if(!this.#value){
            throw new Error('no value');
        } 
        return this.#value
    }
}

// this has to sit outside of the class body
try {
    const val = ButtonToggle.getValue;
    ButtonToggle.value = val
} catch {
    ButtonToggle.value = false
}
Enter fullscreen mode Exit fullscreen mode

正如你所见,我们的try/catch代码必须放在classbody 之外。幸运的是,我们可以用static下面的代码块来代替它:

// method defined outside of the class body
let initVal;

class ButtonToggle{
    #value = false;

    get getValue(){
        if(!this.#value){
            throw new Error('no value');
        } 
        return this.#value
    }

    static {
        initVal = () => {
            this.#value = this.getValue;
        }
    }
}

initVal();
Enter fullscreen mode Exit fullscreen mode

我们static在 our 内部创建了一个块class,它定义了一个在 that 上下文之外声明的函数class。如你所见,该方法将可以访问“#value”,它是private我们类的一个字段。它们将可以访问private方法和字段,无论是 them instance-private(即非staticprivate字段)还是static-private

正则表达式匹配索引

这次升级将允许我们使用d字符来指定我们想要获取 RegExp 匹配的索引(开始和结束)。

我们可以使用Regexp.execString.matchAll来查找匹配列表,它们之间的主要区别在于,Regexp.exec一个接一个地返回结果,而 则String.matchAll返回一个迭代器。让我们在实践中看看它们:

const fruits = 'Fruits: mango, mangosteen, orange'
const regex = /(mango)/g;

// .exec
RegExp(regex).exec(fruits);
// [
//   'mango',
//   index: 8,
//   input: 'Fruits: mango, mangosteen, orange',
//   groups: undefined
// ]

// matchAll
const matches = [...fruits.matchAll(regex)];
matches[0];
// [
//   'mango',
//   'mango',
//   index: 8,
//   input: 'Fruits: mango, mangosteen, orange',
//   groups: undefined
// ]
Enter fullscreen mode Exit fullscreen mode

两者都返回匹配的索引、匹配本身以及初始输入。我们不知道字符串结束的索引,现在可以这样做:

const fruits = 'Fruits: mango, mangosteen, orange'
// /gd instead of the previous /g
const regex = /(mango)/gd;

const matches = [...fruits.matchAll(regex)];
matches[0];

// [
// "mango",
// "mango",
// groups: undefined
// index: 8
// indices:[]
//  [8, 13],
//  [8, 13]
// ]
// groups: undefined
Enter fullscreen mode Exit fullscreen mode

如您所见,它返回 [8,13] 作为字符串中第一次出现“mango”的索引。]

 

顶级 await

await运算符只能在async方法中使用”可能是您经常遇到的错误。在 ES2022 中,我们将能够async在模块中的方法上下文之外使用它。例如,我们可以推迟模块及其父模块的执行,直到导入其他内容。

这在许多情况下都很有用,例如当我们有一个依赖于运行时值的依赖项的动态路径时:

// we need to get the appropriate translation keys based on the language
const translationKeys = await import(`/i18n/${navigator.language}`);
Enter fullscreen mode Exit fullscreen mode

另一个用途是为依赖项提供后备:

let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}
Enter fullscreen mode Exit fullscreen mode

。在()

在 中,JavaScript您可以arr[1]访问 中索引 1 处的值Array,但无法arr[-1]从 的末尾倒数Array。原因是括号语法不仅适用于数组,也适用于对象,在 中obj[-1], 仅引用该 的属性 '-1' Object

使用 .at()方法,我们现在可以轻松访问数组和字符串的任何索引(正数或负数):

const arr = [10,20,30,40];

// same -> 10
arr[1];
arr.at(1);

// same -> 40
arr[arr.length -1];
arr.at(-1);
Enter fullscreen mode Exit fullscreen mode

请注意,负值只是意味着:“从数组末尾开始向后计数”。
 

可访问的 Object.prototype.hasOwnProperty

在 中JavaScript我们已经有一个Object.prototype.hasOwnProperty,但是,正如 MDN 文档所建议的那样,最好不要hasOwnProperty在原型之外使用,因为它不是一个受保护的属性,这意味着可以具有与 无关的object属性hasOwnPropertyObject.prototype.hasOwnProperty

例如:

const obj = {
    hasOwnProperty:()=> {
        return false
    }
}

obj.hasOwnProperty('prop'); // false
Enter fullscreen mode Exit fullscreen mode

正如您所见,我们定义了自己的方法hasOwnProperty,该方法覆盖了原型上的方法,而这个问题并不存在Object.hasOwn()

Object.hasOwn()将我们的Object作为第一个参数,将我们要检查的属性作为第二个参数:

const student = {
    name: 'Mark',
    age: 18
}

Object.hasOwn(student,'age'); // true
Object.hasOwn(student,'grade'); // false
Enter fullscreen mode Exit fullscreen mode

 

你最想尝试的功能是什么?请在下方留言。

如果你想学习 JavaScript 的所有内容,从基础到 ES2022,请查看我的书,可在Github上免费阅读。Educative也有课程。

鏂囩珷鏉ユ簮锛�https://dev.to/albertomontalesi/everything-new-coming-in-es2022-eil
PREV
[教程] 使用 JavaScript 创建番茄钟
NEXT
JavaScript 复制到剪贴板 使用 JavaScript 仅需 10 行代码即可将文本复制到剪贴板