公共類欄位
公共欄位是定義在每個類例項或類建構函式上的可寫、可列舉、可配置的屬性。
語法
class ClassWithField {
instanceField;
instanceFieldWithInitializer = "instance field";
static staticField;
static staticFieldWithInitializer = "static field";
}
還有一些額外的語法限制
- 靜態屬性(欄位或方法)的名稱不能是
prototype。 - 類欄位(靜態或例項)的名稱不能是
constructor。
描述
本頁面詳細介紹了公共例項欄位。
公共例項欄位存在於類的每個已建立例項上。透過宣告公共欄位,可以確保該欄位始終存在,並且類定義更具自文件性。
公共例項欄位在基類構造時(在建構函式體執行之前)新增到例項中,或在子類中 super() 返回之後立即新增。沒有初始化的欄位被初始化為 undefined。像屬性一樣,欄位名可以是計算得出的。
const PREFIX = "prefix";
class ClassWithField {
field;
fieldWithInitializer = "instance field";
[`${PREFIX}Field`] = "prefixed field";
}
const instance = new ClassWithField();
console.log(Object.hasOwn(instance, "field")); // true
console.log(instance.field); // undefined
console.log(instance.fieldWithInitializer); // "instance field"
console.log(instance.prefixField); // "prefixed field"
計算得出的欄位名只在類定義時評估一次。這意味著每個類總是有一組固定的欄位名,兩個例項不能透過計算得出的名稱擁有不同的欄位名。計算表示式中的 this 值是圍繞類定義的 this,並且引用類的名稱會引發 ReferenceError,因為該類尚未初始化。await 和 yield 在此表示式中按預期工作。
class C {
[Math.random()] = 1;
}
console.log(new C());
console.log(new C());
// Both instances have the same field name
在欄位初始化器中,this 指的是正在構建的類例項,而 super 指的是基類的 prototype 屬性,其中包含基類的例項方法,但不包含其例項欄位。
class Base {
baseField = "base field";
anotherBaseField = this.baseField;
baseMethod() {
return "base method output";
}
}
class Derived extends Base {
subField = super.baseMethod();
}
const base = new Base();
const sub = new Derived();
console.log(base.anotherBaseField); // "base field"
console.log(sub.subField); // "base method output"
每次建立新例項時都會評估欄位初始化器表示式。(因為每個例項的 this 值都不同,所以初始化器表示式可以訪問例項特定的屬性。)
class C {
obj = {};
}
const instance1 = new C();
const instance2 = new C();
console.log(instance1.obj === instance2.obj); // false
表示式是同步評估的。您不能在初始化器表示式中使用 await 或 yield。(可以將初始化器表示式看作被隱式包裝在一個函式中。)
由於類的例項欄位在各自的建構函式執行之前新增,因此您可以在建構函式中訪問欄位的值。但是,由於派生類的例項欄位在 super() 返回之後定義,因此基類的建構函式無法訪問派生類的欄位。
class Base {
constructor() {
console.log("Base constructor:", this.field);
}
}
class Derived extends Base {
field = 1;
constructor() {
super();
console.log("Derived constructor:", this.field);
this.field = 2;
}
}
const instance = new Derived();
// Base constructor: undefined
// Derived constructor: 1
console.log(instance.field); // 2
欄位逐個新增。欄位初始化器可以引用其上方的欄位值,但不能引用其下方的欄位值。所有例項和靜態方法都預先新增,並且可以訪問,儘管如果它們引用下方正在初始化的欄位,則呼叫它們可能不會按預期執行。
class C {
a = 1;
b = this.c;
c = this.a + 1;
d = this.c + 1;
}
const instance = new C();
console.log(instance.d); // 3
console.log(instance.b); // undefined
注意: 這對於私有欄位更為重要,因為即使私有欄位在下方宣告,訪問未初始化的私有欄位也會丟擲 TypeError。(如果未宣告私有欄位,則會引發早期 SyntaxError。)
由於類欄位是使用 [[DefineOwnProperty]] 語義(本質上是 Object.defineProperty())新增的,因此派生類中的欄位宣告不會呼叫基類中的 setter。此行為與在建構函式中使用 this.field = … 不同。
class Base {
set field(val) {
console.log(val);
}
}
class DerivedWithField extends Base {
field = 1;
}
const instance = new DerivedWithField(); // No log
class DerivedWithConstructor extends Base {
constructor() {
super();
this.field = 1;
}
}
const instance2 = new DerivedWithConstructor(); // Logs 1
示例
使用類欄位
類欄位不能依賴於建構函式的引數,因此欄位初始化器通常為每個例項評估為相同的值(除非相同的表示式每次都可以評估為不同的值,例如 Math.random() 或物件初始化器)。
class Person {
name = nameArg; // nameArg is out of scope of the constructor
constructor(nameArg) {}
}
class Person {
// All instances of Person will have the same name
name = "Dragomir";
}
然而,即使宣告一個空的類欄位也是有益的,因為它表明了該欄位的存在,這允許型別檢查器和人工讀者靜態分析類的形狀。
class Person {
name;
age;
constructor(name, age) {
this.name = name;
this.age = age;
}
}
上面的程式碼看起來是重複的,但考慮 this 動態變異的情況:顯式欄位宣告清楚地表明瞭哪些欄位肯定會出現在例項上。
class Person {
name;
age;
constructor(properties) {
Object.assign(this, properties);
}
}
由於初始化器在基類執行後才評估,您可以訪問基類建構函式建立的屬性。
class Person {
name;
age;
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class Professor extends Person {
name = `Professor ${this.name}`;
}
console.log(new Professor("Radev", 54).name); // "Professor Radev"
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # prod-FieldDefinition |
瀏覽器相容性
載入中…