Поля классов

Объявление публичных и приватных полей является экспериментальной разработкой, предложенной в коммитете стандартов JavaScript TC39. Поддержка браузерами ограничена, но данное нововведение можно использовать посредством транспиляторов (например, Babel). Смотрите информацию о совместимости ниже.

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

И статические, и публичные поля являются изменяемыми, перечисляемыми, настраиваемыми свойствами. Таким образом, в отличие от приватных полей, они участвуют в прототипном наследовании.

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

Публичные статические поля полезны тогда, когда необходимо существование одного единственного поля для всего класса, а не для каждого созданного экземпляра по отдельности. Это полезно для кеша, конфигураций или любых прочих данных, которые одинаковы для всех экземпляров.

Публичные статические поля объявляются при помощи ключевого слова static. Они добавляются в конструктор класса во время его создания с помощью Object.defineProperty. Доступ также осуществляется через конструктор класса.

class ClassWithStaticField {
  static staticField = 'static field';
}

console.log(ClassWithStaticField.staticField);
// Ожидаемый вывод: "static field"

Поля без инициализации имеют значение undefined.

class ClassWithStaticField {
  static staticField;
}

console.assert(ClassWithStaticField.hasOwnProperty('staticField'));
console.log(ClassWithStaticField.staticField);
// Ожидаемый вывод: "undefined"

Публичные статические поля не переопределяются в наследниках класса, а могут быть доступны через иерархию прототипов.

class ClassWithStaticField {
  static baseStaticField = 'base field';
}

class SubClassWithStaticField extends ClassWithStaticField {
  static subStaticField = 'sub class field';
}

console.log(SubClassWithStaticField.subStaticField);
// Ожидаемый вывод: "sub class field"

console.log(SubClassWithStaticField.baseStaticField);
// Ожидаемый вывод: "base field"

При определении полей this ссылается на конструктор класса. Также можно обратиться к нему по имени и использовать super для получения конструктора базового класса, если он существует.

class ClassWithStaticField {
  static baseStaticField = 'base static field';
  static anotherBaseStaticField = this.baseStaticField;

  static baseStaticMethod() { return 'base static method output'; }
}

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

console.log(ClassWithStaticField.anotherBaseStaticField);
// Ожидаемый вывод: "base static field"

console.log(SubClassWithStaticField.subStaticField);
// Ожидаемый вывод: "base static method output"

Публичные поля экземпляра

Такие публичные поля имеются у каждого экземпляра данного класса. Объявляя публичные поля, мы можем гарантировать, что поле всегда актуально, а объявление класса является более самодокументированным.

Публичные поля экземпляра добавляются через Object.defineProperty либо перед тем, как будет исполнено тело конструктора в базовом классе, либо после того, как завершится super() в классе наследнике.

class ClassWithInstanceField {
  instanceField = 'instance field';
}

const instance = new ClassWithInstanceField();
console.log(instance.instanceField);
// Ожидаемый вывод: "instance field"

Поля без инициализации имеют значение undefined.

class ClassWithInstanceField {
  instanceField;
}

const instance = new ClassWithInstanceField();
console.assert(instance.hasOwnProperty('instanceField'));
console.log(instance.instanceField);
// Ожидаемый вывод: "undefined"

Как и свойства, названия полей могут вычисляться.

const PREFIX = 'prefix';

class ClassWithComputedFieldName {
    [`${PREFIX}Field`] = 'prefixed field';
}

const instance = new ClassWithComputedFieldName();
console.log(instance.prefixField);
// Ожидаемый вывод: "prefixed field"

При определении полей this ссылается на создающийся экземпляр класса. Как и в публичных методах экземпляра, получить доступ к прототипу базового класса можно с помощью super.

class ClassWithInstanceField {
  baseInstanceField = 'base field';
  anotherBaseInstanceField = this.baseInstanceField;
  baseInstanceMethod() { return 'base method output'; }
}

class SubClassWithInstanceField extends ClassWithInstanceField {
  subInstanceField = super.baseInstanceMethod();
}

const base = new ClassWithInstanceField();
const sub = new SubClassWithInstanceField();

console.log(base.anotherBaseInstanceField);
// Ожидаемый вывод: "base field"

console.log(sub.subInstanceField);
// Ожидаемый вывод: "base method output"

Публичные методы

Публичные статические методы

Ключевое слово static объявляет статический метод класса. Статические методы не вызываются из экземпляра, вместо этого они вызывается из самого класса. Чаще всего это какие-либо служебные функции, такие как функции создания или копирования объектов.

Статические методы добавляются в конструктор класса с помощью Object.defineProperty во время его создания. Эти методы - изменяемые, неперечисляемые и настраеваемые свойства объекта.

Публичные методы экземпляра

Как и следует из названия, публичные методы экземпляра это методы, доступные для вызова из экземпляров.

class ClassWithPublicInstanceMethod {
  publicMethod() {
    return 'hello world';
  }
}

const instance = new ClassWithPublicInstanceMethod();
console.log(instance.publicMethod());
// Ожидаемый вывод: "hello worl​d"

Публичные методы добавляются в прототип класса во время его создания с помощью Object.defineProperty. Они изменяемы, неперечисляемы и настраиваемы.

Вы можете использовать генераторы, асинхронные функции и асинхронные генераторы.

class ClassWithFancyMethods {
  *generatorMethod() { }
  async asyncMethod() { }
  async *asyncGeneratorMethod() { }
}

Внутри методов экземпляра, this ссылается на сам экземпляр. классах наследниках, super дает доступ к прототипу базового класса, позволяя вызывать его методы.

class BaseClass {
  msg = 'hello world';
  basePublicMethod() {
    return this.msg;
  }
}

class SubClass extends BaseClass {
  subPublicMethod() {
    return super.basePublicMethod();
  }
}

const instance = new SubClass();
console.log(instance.subPublicMethod());
// Ожидаемый вывод: "hello worl​d"

Геттеры и сеттеры это специальные методы, которые привязаны к свойствам класса и которые вызываются, когда к свойсту обращаются или записывают. Используйте get и set для объявления публичных геттеров и сеттеров экземпляра.

class ClassWithGetSet {
  #msg = 'hello world';
  get msg() {
    return this.#msg;
  }
  set msg(x) {
    this.#msg = `hello ${x}`;
  }
}

const instance = new ClassWithGetSet();
console.log(instance.msg);
// Ожидаемый вывод: "hello worl​d"

instance.msg = 'cake';
console.log(instance.msg);
// Ожидаемый вывод: "hello cake"

Приватные поля

Приватные статические поля

Приватные поля доступны через конструктор внутри объявления самого класса.

Также сохраняется ограничение на вызов статических полей только внутри статических методов.

class ClassWithPrivateStaticField {
  static #PRIVATE_STATIC_FIELD;

  static publicStaticMethod() {
    ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42;
    return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD;
  }
}

assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);

Приватные статические поля добавляются в конструктор на этапе оценки класса.

Существует ограничение происхождения приватных статических полей. Только класс, который объявляет приватное статическое поле, может обращаться к нему. Это может привести к неожиданному поведению при использовании this.

class BaseClassWithPrivateStaticField {
  static #PRIVATE_STATIC_FIELD;

  static basePublicStaticMethod() {
    this.#PRIVATE_STATIC_FIELD = 42;
    return this.#PRIVATE_STATIC_FIELD;
  }
}

class SubClass extends BaseClassWithPrivateStaticField { }

assertThrows(() => SubClass.basePublicStaticMethod(), TypeError);

Private instance fields

Private instance fields are declared with # names ( pronounced "hash names"), which are identifiers prefixed with #. The # is a part of the name itself and is used for declaration and accessing as well.

The encapsulation is enforced by the language. It is a syntax error to refer to # names not in scope.

class ClassWithPrivateField {
  #privateField;
  
  constructor() {
    this.#privateField = 42;
    this.#randomField = 666; # Syntax error
  }
}

const instance = new ClassWithPrivateField();
instance.#privateField === 42; // Syntax error

Private Methods

Private static methods

Like their public equivalent, private static methods are called on the class, not instances of the class. Like private static fields, they are only accessible from inside the class declaration.

Private static methods may be generator, async and async generator functions.

class ClassWithPrivateStaticMethod {
    static #privateStaticMethod() {
        return 42;
    }

    static publicStaticMethod() {
        return ClassWithPrivateStaticMethod.#privateStaticMethod();
    }
}

assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);

Private instance methods

Private instance methods are methods available on class instances whose access is restricted in the same manner as private instance fields.

class ClassWithPrivateMethod {
  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
      return #privateMethod();
  }
}

const instance = new ClassWithPrivateMethod();
console.log(instance.getPrivateMessage());
// expected output: "hello worl​d"

Private instance methods may be generator, async or async generator functions. Private getters and setters are also possible:

class ClassWithPrivateAccessor {
  #message;

  get #decoratedMessage() {
    return `✨${this.#message}✨`;
  }
  set #decoratedMessage(msg) {
    this.#message = msg;
  }

  constructor() {
    this.#decoratedMessage = 'hello world';
    console.log(this.#decoratedMessage);
  }
}

new ClassWithPrivateAccessor();
// expected output: "✨hello worl​d✨"

Browser compatibility

Public class fields

Update compatibility data on GitHub
КомпьютерыМобильныеServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung InternetNode.js
Public class fieldsChrome Полная поддержка 72Edge Нет поддержки НетFirefox Полная поддержка 69IE Нет поддержки НетOpera Полная поддержка 60Safari Нет поддержки НетWebView Android Полная поддержка 72Chrome Android Полная поддержка 72Firefox Android Нет поддержки НетOpera Android Полная поддержка 51Safari iOS Нет поддержки НетSamsung Internet Android Нет поддержки Нетnodejs Полная поддержка 12.0.0

Легенда

Полная поддержка  
Полная поддержка
Нет поддержки  
Нет поддержки

Private class fields

Update compatibility data on GitHub
КомпьютерыМобильныеServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung InternetNode.js
Private class fieldsChrome Полная поддержка 74Edge Нет поддержки НетFirefox Нет поддержки НетIE Нет поддержки НетOpera Полная поддержка 62Safari Нет поддержки НетWebView Android Полная поддержка 74Chrome Android Полная поддержка 74Firefox Android Нет поддержки НетOpera Android Полная поддержка 53Safari iOS Нет поддержки НетSamsung Internet Android Нет поддержки Нетnodejs Полная поддержка 12.0.0

Легенда

Полная поддержка  
Полная поддержка
Нет поддержки  
Нет поддержки

See also