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

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

ES2022 позволяет вам определять частные поля для класса. Чтобы определить приватное поле, вы добавляете перед именем поля знак #.

Например, следующий код определяет класс Circle с закрытым radius поля:

class Circle {
  #radius;
  constructor(value) {
    this.#radius = value;
  }
  get area() {
    return Math.PI * Math.pow(this.#radius, 2);
  }
}

В этом примере:

  • Во-первых, определите приватное поле #radius в теле класса.
  • Во-вторых, инициализируйте поле #radius в конструкторе аргументом.
  • В-третьих, вычислите площадь круга, обратившись к частному полю #radius в методе получения.

Следующий код создает новый экземпляр класса Circle и вычисляет его площадь:

let circle = new Circle(10);
console.log(circle.area); // 314.1592653589793

Поскольку #radius является приватным полем, вы можете получить к нему доступ только внутри класса Circle. Другими словами, поле невидимо вне класса Circle.

Использование геттера и сеттера для доступа к закрытым полям

Следующий код переопределяет класс Circle, добавляя геттер и сеттер radius для предоставления доступа к частному полю #radius :

class Circle {
  #radius = 0;
  constructor(radius) {
    this.radius = radius;
  }
  get area() {
    return Math.PI * Math.pow(this.radius, 2);
  }
  set radius(value) {
    if(typeof value === 'number' && value > 0) {
      this.#radius = value;
    } else {
      throw 'The radius must be a positive number';
    }
  }
  get radius() {
    return this.#radius;
  }
}

Как это работает.

  • Установщик radius проверяет аргумент, прежде чем назначать его частному полю #radius. Если аргумент не является положительным числом, установщик выдает ошибку.
  • Получатель radius возвращает значение частного поля #radius.
  • Конструктор вызывает установщик radius, чтобы присвоить аргумент частному полю #radius.

Частные поля и подклассы

Закрытые поля доступны только внутри класса, в котором они определены. Кроме того, они недоступны из подклассов. Например, следующий код определяет класс Cylinder, который расширяет класс Circle :

class Cylinder extends Circle {
  #height;
  constructor(radius, height) {
    super(radius);
    this.#height = height;

    // cannot access the #radius of the Circle class here
  }
}

Если вы попытаетесь получить доступ к приватному полю #radius в классе Cylinder, вы получите SyntaxError.

Оператор in : проверка наличия приватных полей

Чтобы проверить, есть ли у объекта закрытое поле внутри класса, вы используете оператор in :

fieldName in objectName

Например, следующий код добавляет к классу Circle статический метод hasRadius(), который использует оператор in для проверки того, имеет ли объект circle закрытое поле #radius :

class Circle {
  #radius = 0;
  constructor(radius) {
    this.radius = radius;
  }
  get area() {
    return Math.PI * Math.pow(this.radius, 2);
  }
  set radius(value) {
    if (typeof value === 'number' && value > 0) {
      this.#radius = value;
    } else {
      throw 'The radius must be a positive number';
    }
  }
  get radius() {
    return this.#radius;
  }
  static hasRadius(circle) {
    return #radius in circle;
  }
}

let circle = new Circle(10);

console.log(Circle.hasRadius(circle));

Выход:

true

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

В следующем примере показано, как использовать статическое приватное поле:

class Circle {
  #radius = 0;
  static #count = 0;
  constructor(radius) {
    this.radius = radius;
    Circle.#count++;
  }
  get area() {
    return Math.PI * Math.pow(this.radius, 2);
  }
  set radius(value) {
    if(typeof value === 'number' && value > 0) {
      this.#radius = value;
    } else {
      throw 'The radius must be a positive number';
    }
  }
  get radius() {
    return this.#radius;
  }
  static hasRadius(circle) {
    return #radius in circle;
  }
  static getCount() {
    return Circle.#count;
  }
}

let circles = [new Circle(10), new Circle(20), new Circle(30)];

console.log(Circle.getCount());

Как это работает:

  • Во-первых, добавьте закрытое статическое поле #count в класс Circle и инициализируйте его значение нулем:
static #count = 0;
  • Во-вторых, увеличьте #count на единицу в конструкторе:
Circle.#count++;
  • В-третьих, определите статический метод, который возвращает значение закрытого статического поля #count :
static getCount() {
    return Circle.#count;
}
  • Наконец, создайте три экземпляра класса Circle и выведите значение count на консоль:
let circles = [new Circle(10), new Circle(20), new Circle(30)];
console.log(Circle.getCount());

Заключение

  • Поставьте перед именем поля знак #, чтобы сделать его закрытым.
  • Частные поля доступны только внутри класса, а не снаружи класса или подклассов.
  • Используйте оператор in, чтобы проверить, есть ли у объекта закрытое поле в Javascript.
Рейтинг
( Пока оценок нет )
Александр Русаков / автор статьи
Программист, разработчик, 12 лет опыта работы в крупных компаниях. Быстро освоил typescript, делюсь своими знаниями на страницах этого сайта.
Загрузка ...
JavaScript и TypeScript