Spec-Zone.ru › JavaScript

Публичные поля класса

Базовый уровень Широко доступен

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и в различных версиях браузеров. Она доступна в браузерах с марта 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"

Спецификации

Спецификация
Спецификация языка ECMAScript® 2027
# prod-FieldDefinition

Совместимость с браузерами

Настольные компьютеры Мобильные устройства Сервер
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.1–16Скобки в инициализаторах полей могут привести к ReferenceError. См. ошибку 236843.
14–14.1Не поддерживает публичные статические поля. См. ошибку 194095.
72
79
51
16
14.5–16Скобки в инициализаторах полей могут привести к ReferenceError. См. ошибку 236843.
14–14.5Не поддерживает публичные статические поля. См. ошибку 194095.
11.0
72
16
14.5–16Скобки в инициализаторах полей могут привести к ReferenceError. См. ошибку 236843.
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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API