Публичные поля класса
Базовый уровень Широко доступен
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и в различных версиях браузеров. Она доступна в браузерах с марта 2016 года.
Публичные поля — это записываемые, перечисляемые и конфигурируемые свойства, определенные для каждого экземпляра класса или конструктора класса.
Синтаксис
class ClassWithField {
instanceField;
instanceFieldWithInitializer = "instance field";
static staticField;
static staticFieldWithInitializer = "static field";
}
Существуют некоторые дополнительные ограничения синтаксиса:
- Имя статического свойства (поля или метода) не может быть
prototype. - Имя поля класса (статического или экземплярного) не может быть
constructor.
Описание
На этой странице подробно представлены публичные поля экземпляра.
- Для публичных статических полей см.
static. - Для приватных полей см. приватные элементы.
- Для публичных методов см. определения методов.
- Для публичных акцессоров см. геттер и сеттер.
Публичные поля экземпляра существуют в каждом созданном экземпляре класса. Объявляя публичное поле, вы можете гарантировать, что поле всегда присутствует, а определение класса более самодокументируемо.
Публичные поля экземпляра добавляются в экземпляр либо во время конструирования в базовом классе (до выполнения тела конструктора), либо сразу после того, как 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()), объявления полей в производных классах не вызывают сеттеры в базовом классе. Такое поведение отличается от использования 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
Примечание: До того, как спецификация полей класса была финализирована с семантикой [[DefineOwnProperty]], большинство транспиляторов, включая Babel и tsc, преобразовывали поля класса в форму DerivedWithConstructor, что привело к тонким ошибкам после стандартизации полей класса.
Примеры
Использование полей класса
Поля класса не могут зависеть от аргументов конструктора, поэтому инициализаторы полей обычно вычисляют одно и то же значение для каждого экземпляра (если только одно и то же выражение не может вычислить разные значения каждый раз, например, 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"
Спецификации
Совместимость с браузерами
| Настольные компьютеры | Мобильные устройства | Сервер | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
public_class_fields |
72 |
79 |
69 |
60 |
16
14–14.1Не поддерживает публичные статические поля. См. ошибку 194095. |
72 |
79 |
51 |
16
14–14.5Не поддерживает публичные статические поля. См. ошибку 194095. |
11.0 |
72 |
16
14–14.5Не поддерживает публичные статические поля. См. ошибку 194095. |
1.0.0 |
1.0 |
12.0.0 |
См. также
- Руководство по использованию классов
- Классы
- Приватные элементы
class- Семантика всех элементов класса JS от Шу-ю Гуо (2018)
- Публичные и приватные поля класса на v8.dev (2018)
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields