静态初始化块

Baseline 已广泛支持

此功能已成熟,并可在许多设备和浏览器版本上运行。自 2023 年 3 月以来,它已在各种浏览器中可用。

静态初始化块声明在 class 内部。它包含在类初始化期间需要评估的语句。这允许比 static 属性更灵活的初始化逻辑,例如使用 try...catch 或从单个值设置多个字段。初始化在当前类声明的上下文中执行,可以访问私有状态,这允许类与其在同一作用域中声明的其他类或函数共享其私有元素的信息(类似于 C++ 中的“友元”类)。

试一试

class ClassWithStaticInitializationBlock {
  static staticProperty1 = "Property 1";
  static staticProperty2;
  static {
    this.staticProperty2 = "Property 2";
  }
}

console.log(ClassWithStaticInitializationBlock.staticProperty1);
// Expected output: "Property 1"
console.log(ClassWithStaticInitializationBlock.staticProperty2);
// Expected output: "Property 2"

语法

js
class ClassWithSIB {
  static {
    // …
  }
}

描述

如果没有静态初始化块,复杂的静态初始化可以通过在类声明后调用静态方法来实现

js
class MyClass {
  static init() {
    // Access to private static fields is allowed here
  }
}

MyClass.init();

然而,这种方法将实现细节(init() 方法)暴露给类的使用者。另一方面,在类外部声明的任何初始化逻辑都无法访问私有静态字段。静态初始化块允许在类内部声明任意初始化逻辑,并在类评估期间执行。

一个 class 可以在其类主体中拥有任意数量的 static {} 初始化块。它们与任何穿插的静态字段初始化器一起,按照声明的顺序进行评估。任何超类的静态初始化都会首先执行,然后才是其子类的静态初始化。

静态块内声明的变量作用域仅限于该块。这包括 varfunctionconstlet 声明。var 声明不会被提升到静态块之外。

js
var y = "Outer y";

class A {
  static field = "Inner y";
  static {
    // var y only hoisted inside block
    console.log(y); // undefined <-- not 'Outer y'

    var y = this.field;
  }
}

// var y defined in static block is not hoisted
// outside the block
console.log(y); // 'Outer y'

静态块内的 this 指的是类的构造函数对象。super.property 可用于访问超类的静态属性。但是请注意,在类静态初始化块中调用 super(),或使用 arguments 对象是语法错误。

语句是同步评估的。你不能在此块中使用 awaityield。(可以将初始化语句看作是被隐式包裹在一个函数中。)

静态块的作用域嵌套在类主体的词法作用域之内,并且可以访问在类内部声明的私有名称,而不会导致语法错误。

静态字段初始化器和静态初始化块是逐个评估的。初始化块可以引用其上方的字段值,但不能引用其下方的字段值。所有静态方法都会预先添加并可以访问,尽管如果它们引用当前块下方的字段,则调用它们可能不会按预期运行。

注意: 这对于私有静态字段更为重要,因为即使私有字段在下方声明,访问未初始化的私有字段也会抛出 TypeError。(如果私有字段未声明,则会是一个早期 SyntaxError。)

静态初始化块不能有装饰器(类本身可以有)。

示例

多个块

下面的代码演示了一个包含静态初始化块和穿插的静态字段初始化器的类。输出显示块和字段是按执行顺序评估的。

js
class MyClass {
  static field1 = console.log("static field1");
  static {
    console.log("static block1");
  }
  static field2 = console.log("static field2");
  static {
    console.log("static block2");
  }
}
// 'static field1'
// 'static block1'
// 'static field2'
// 'static block2'

请注意,任何超类的静态初始化都会首先执行,然后才是其子类的静态初始化。

使用 this 和 super

静态块内的 this 指的是类的构造函数对象。此代码显示了如何访问公共静态字段。

js
class A {
  static field = "static field";
  static {
    console.log(this.field);
  }
}
// 'static field'

可以在 static 块内使用 super.property 语法来引用超类的静态属性。

js
class A {
  static field = "static field";
}

class B extends A {
  static {
    console.log(super.field);
  }
}
// 'static field'

访问私有元素

下面的示例展示了如何从类外部的对象授予对类私有实例字段的访问权限(示例来自 v8.dev 博客

js
let getDPrivateField;

class D {
  #privateField;
  constructor(v) {
    this.#privateField = v;
  }
  static {
    getDPrivateField = (d) => d.#privateField;
  }
}

console.log(getDPrivateField(new D("private"))); // 'private'

规范

规范
ECMAScript® 2026 语言规范
# prod-ClassStaticBlock

浏览器兼容性

另见