Геттеры и сеттеры: управление доступом к свойствам

Зачем нужны геттеры и сеттеры?

Представь, что у тебя есть объект user с полем age:

const user = {
  name: "Alex",
  age: 25
};

Что произойдёт, если кто-то установит отрицательный возраст? 🤔

user.age = -100; // Ой-ой, так не годится!

Геттеры и сеттеры — это "сторожа" для свойств объекта. Они позволяют контролировать:

  • Чтение свойства (геттер)
  • Запись свойства (сеттер)

Базовый синтаксис

Вот как выглядит простейший геттер и сеттер:

const user = {
  _age: 25, // Подчеркём — это "приватное" поле

  get age() {
    return this._age;
  },

  set age(value) {
    if (value < 0) {
      console.log("Возраст не может быть отрицательным!");
      return;
    }
    this._age = value;
  }
};

Теперь попробуем:

user.age = -30; // "Возраст не может быть отрицательным!"
console.log(user.age); // 25 (значение не изменилось)

💡 Обрати внимание: мы используем _age как внутреннее поле, а публичный интерфейс — просто age.


Умные свойства

Геттеры и сеттеры делают свойства "умными". Вот несколько крутых применений:

1. Автоматическое форматирование

const product = {
  price: 100,

  get formattedPrice() {
    return `$${this.price}`;
  }
};

console.log(product.formattedPrice); // "$100"

2. Валидация данных

const person = {
  _birthYear: 1990,

  get age() {
    return new Date().getFullYear() - this._birthYear;
  },

  set birthYear(value) {
    if (value > new Date().getFullYear()) {
      throw new Error("Год рождения не может быть в будущем!");
    }
    this._birthYear = value;
  }
};

3. Вычисляемые свойства

const rectangle = {
  width: 10,
  height: 5,

  get area() {
    return this.width * this.height;
  }
};

console.log(rectangle.area); // 50

Геттеры без сеттеров

Иногда нужно сделать свойство "только для чтения":

const constants = {
  get PI() {
    return 3.14159;
  }
};

console.log(constants.PI); // 3.14159
constants.PI = 3; // Ничего не произойдёт (в strict mode будет ошибка)

Совместимость с existing-кодом

Геттеры/сеттеры полностью прозрачны для внешнего кода:

class User {
  constructor(name) {
    this.name = name;
    this._accessCount = 0;
  }

  get accessCount() {
    return ++this._accessCount;
  }
}

const admin = new User("Danila");
console.log(admin.accessCount); // 1
console.log(admin.accessCount); // 2

🔥 Кстати, в классах синтаксис геттеров/сеттеров особенно элегантен!


Когда стоит использовать?

Ситуация Подходит?
Нужна валидация ✅ Идеально
Вычисляемые значения ✅ Отлично
Логирование доступа ✅ Хорошо
Простые публичные поля ❌ Избыточно

Подводные камни

1. Рекурсия: Не называй геттер так же, как внутреннее свойство!

// ❌ Ошибка: бесконечная рекурсия!
const oops = {
  get value() {
    return this.value; // Вызывает самого себя!
  }
};

2. Производительность: Геттеры/сеттеры медленнее прямого доступа к полям (но в 99% случаев это неважно).


Практическое задание

Создай объект temperature с:

  • Приватным полем _celsius
  • Геттером/сеттером celsius
  • Геттером fahrenheit, который преобразует температуру

Решение:

const temperature = {
  _celsius: 0,

  get celsius() {
    return this._celsius;
  },

  set celsius(value) {
    if (value < -273.15) {
      throw new Error("Температура ниже абсолютного нуля!");
    }
    this._celsius = value;
  },

  get fahrenheit() {
    return this._celsius * 9/5 + 32;
  }
};

Проверка:

temperature.celsius = 25;
console.log(temperature.fahrenheit); // 77

Финал

Геттеры и сеттеры — мощный инструмент для:

  • Контроля доступа к данным
  • Валидации значений
  • Создания "умных" свойств

Используй их там, где нужно добавить логику вокруг обычных свойств объекта! 🔥

Скрыть рекламу навсегда

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty