static

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2016.

static 关键字定义了静态方法或字段,或静态初始化块(有关这种用法的更多信息,请参阅链接)。静态属性不能在类的实例上直接访问。相反,它们是在类本身上被访问的。

静态方法通常是实用函数,如创建或克隆对象的函数,而静态属性则适用于缓存、固定配置或其他不需要跨实例复制的数据。

备注: 在类的上下文中,MDN Web 文档内容交替使用属性和字段这两个术语。

尝试一下

语法

js
class ClassWithStatic {
  static staticField;
  static staticFieldWithInitializer = value;
  static staticMethod() {
    // …
  }
}

还有一些额外的语法限制:

  • 静态属性(字段或方法)的名称不能是 prototype
  • 类字段(静态或实例)的名称不能是 constructor

描述

本页介绍类的公有静态属性,包括静态方法、静态访问器和静态字段。

公有静态特性是使用 static 关键字声明的。在类求值时,使用 [[DefineOwnProperty]] 语义(本质上是 Object.defineProperty())将它们添加到类构造函数中。类构造函数会再次访问它们。

静态方法通常是实用函数,例如创建或克隆实例的函数。当你希望一个字段在每个类中只存在一次,而不是在你创建的每个类实例中都存在时,公有静态字段就很有用。这对缓存、固定配置或其他不需要在实例间复制的数据非常有用。

静态字段名称可以计算。计算表达式中的 this 值是类定义周围的 this,而引用类的名称则会导致 ReferenceError,因为类尚未初始化。在此表达式中,awaityield 按预期工作。

静态字段可以有初始化器。没有初始化器的静态字段将被初始化为 undefined。公有静态字段不会在子类中重新初始化,但可以通过原型链访问。

js
class ClassWithStaticField {
  static staticField;
  static staticFieldWithInitializer = "静态字段";
}

class SubclassWithStaticField extends ClassWithStaticField {
  static subStaticField = "子类的字段";
}

console.log(Object.hasOwn(ClassWithStaticField, "staticField")); // true
console.log(ClassWithStaticField.staticField); // undefined
console.log(ClassWithStaticField.staticFieldWithInitializer); // "静态字段"
console.log(SubclassWithStaticField.staticFieldWithInitializer); // "静态字段"
console.log(SubclassWithStaticField.subStaticField); // "子类的字段"

在字段初始化器中,this 指向当前类(也可通过其名称访问),super 指向基类构造函数。

js
class ClassWithStaticField {
  static baseStaticField = "基类静态字段";
  static anotherBaseStaticField = this.baseStaticField;

  static baseStaticMethod() {
    return "基类静态方法输出";
  }
}

class SubClassWithStaticField extends ClassWithStaticField {
  static subStaticField = super.baseStaticMethod();
}

console.log(ClassWithStaticField.anotherBaseStaticField); // "基类静态字段"
console.log(SubClassWithStaticField.subStaticField); // "基类静态方法输出"

表达式是同步求值的。不能在初始化表达式中使用 awaityield。(将初始化表达式视为隐式封装在函数中。)

静态字段初始化器和静态初始化块是逐个求值的。字段初始化器可以引用其上的字段值,但不能引用其下的字段值。所有静态方法都会事先添加并可被访问,但如果它们引用的字段在被初始化的字段的下方,则调用它们时可能会出现与预期不符的情况。

备注: 对于私有静态字段而言,这一点更为重要,因为访问未初始化的私有字段会抛出 TypeError,即使该私有字段已在下面声明。(如果未声明私有字段,则会提前抛出 SyntaxError。)

示例

在类中使用静态成员

下面的例子说明了这几点:

  1. 静态方法如何在类上实现。
  2. 具有静态成员的类,可以被子类化。
  3. 什么情况下静态方法可以调用,什么情况下不能调用。
js
class Triple {
  static customName = "三倍器";
  static description = "我可以让你提供的任何数变为它的三倍";
  static calculate(n = 1) {
    return n * 3;
  }
}

class SquaredTriple extends Triple {
  static longDescription;
  static description = "我可以让你提供的任何数变为其三倍的平方";
  static calculate(n) {
    return super.calculate(n) * super.calculate(n);
  }
}

console.log(Triple.description); // '我可以让你提供的任何数变为它的三倍'
console.log(Triple.calculate()); // 3
console.log(Triple.calculate(6)); // 18

let tp = new Triple();

console.log(SquaredTriple.tripple(3)); // 81(不会受父类实例化的影响)
console.log(SquaredTriple.description); // '我可以让你提供的任何数变为其三倍的平方'
console.log(SquaredTriple.longDescription); // undefined
console.log(SquaredTriple.customName); // '三倍器'

// 抛出错误,因为 calculate() 是静态成员,而不是实例成员。
console.log(tp.calculate()); // 'tp.calculate 不是一个函数'

从另一个静态方法调用静态成员

为了在同一类的另一个静态方法中调用静态方法或属性,可以使用 this 关键字。

js
class StaticMethodCall {
  static staticProperty = "静态属性";
  static staticMethod() {
    return `静态方法和${this.staticProperty}被调用`;
  }
  static anotherStaticMethod() {
    return `从另外一个静态方法而来的${this.staticMethod()}`;
  }
}
StaticMethodCall.staticMethod();
// '静态方法和静态属性被调用'

StaticMethodCall.anotherStaticMethod();
// '从另外一个静态方法而来的静态方法和静态属性被调用'

从类的构造函数和其他方法中调用静态成员

静态成员不能使用 this 关键字从非静态方法直接访问静态成员。你需要使用类名来调用 classname.static_method_name()CLASSNAME.STATIC_PROPERTY_NAME,或将 this.constructor.STATIC_Method_NAME()this.constructor.STATIC_PROPERTY_NAME 来作为 constructor 的属性调用。

js
class StaticMethodCall {
  constructor() {
    console.log(StaticMethodCall.staticProperty); // '静态属性'
    console.log(this.constructor.staticProperty); // '静态属性'
    console.log(StaticMethodCall.staticMethod()); // '静态方法已调用'
    console.log(this.constructor.staticMethod()); // '静态方法已调用'
  }

  static staticProperty = "静态属性";
  static staticMethod() {
    return "静态方法已调用";
  }
}

规范

Specification
ECMAScript Language Specification
# sec-class-definitions

浏览器兼容性

Report problems with this compatibility data on GitHub
desktopmobileserver
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Deno
Node.js
static

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
Has more compatibility info.

参见