Skip to main content

Геттери та сеттери в об'єкті

Геттер і сеттер, це функції-аксесори, які прив'язані до імені властивості: геттер спрацьовує на читанні, сеттер, на присвоєнні. Їх оголошують просто в об'єктному літералі через get і set або додають до наявного об'єкта через Object.defineProperty().

Теорія

TL;DR

  • Геттер (getter), функція, яка викликається під час читання властивості.
  • Сеттер (setter), функція, яка викликається під час присвоєння значення.
  • Синтаксис у літералі: get prop() { ... } і set prop(value) { ... }.
  • Ззовні властивість виглядає звичайною: obj.prop і obj.prop = 5, без дужок виклику.
  • Головні сценарії: обчислювані властивості, валідація вхідних даних, інкапсуляція внутрішнього поля.
  • Object.defineProperty() дає те саме, але дозволяє ще й налаштувати enumerable, configurable тощо.

Швидкий приклад

javascript
const user = { firstName: 'Maria', lastName: 'Kovalenko', get fullName() { return `${this.firstName} ${this.lastName}`; } }; console.log(user.fullName); // "Maria Kovalenko", викликався геттер

Що таке геттер і сеттер

  • Геттер (getter), це функція, яка викликається при читанні властивості.
  • Сеттер (setter), це функція, яка викликається при присвоєнні значення.

Вони дозволяють зробити властивості обчислюваними або контролювати, що саме записується в об'єкт. Значення геттер не зберігає: він рахує його щоразу заново з інших полів.

Синтаксис усередині об'єктного літерала

javascript
const user = { firstName: 'Maria', lastName: 'Kovalenko', // геттер get fullName() { return `${this.firstName} ${this.lastName}`; }, // сеттер set fullName(value) { const [first, last] = value.split(' '); this.firstName = first; this.lastName = last; } }; console.log(user.fullName); // "Maria Kovalenko", викликався getter user.fullName = 'Oleh Petrenko'; // викликався setter console.log(user.firstName); // "Oleh" console.log(user.lastName); // "Petrenko"

Як це працює:

ОпераціяЩо відбувається
user.fullNameвикликає геттер, повертає значення
user.fullName = '...'викликає сеттер, обробляє присвоєння

Тобто fullName виглядає як звичайна властивість, але за нею приховані функції. Сеттер завжди приймає рівно один параметр, значення, яке присвоюють.

Приклад з перевіркою значення (валідацією)

javascript
const product = { _price: 0, // внутрішнє сховище get price() { return this._price; }, set price(value) { if (value < 0) { console.error('Price cannot be negative'); return; } this._price = value; } }; product.price = 500; // setter спрацював console.log(product.price); // 500, getter спрацював product.price = -10; // відхилено, значення не змінилося

Зазвичай геттери та сеттери працюють із «внутрішніми» полями, імена яких починаються з _. Це домовленість, а не захист мови: доступ до product._price залишається відкритим. Якщо потрібна справжня приватність, використовуйте приватні поля класів #price.

Через Object.defineProperty(), альтернативний спосіб

javascript
const user = { firstName: 'Maria', lastName: 'Kovalenko' }; Object.defineProperty(user, 'fullName', { get() { return `${this.firstName} ${this.lastName}`; }, set(value) { const [first, last] = value.split(' '); this.firstName = first; this.lastName = last; } }); console.log(user.fullName); // "Maria Kovalenko" user.fullName = 'Oleh Petrenko'; console.log(user.firstName); // "Oleh"

Цей спосіб гнучкіший: можна налаштувати додаткові атрибути (enumerable, configurable тощо). Зверніть увагу, що за замовчуванням Object.defineProperty() робить властивість неперелічуваною, тоді як у літералі аксесор перелічуваний.

Підсумкова таблиця

ЕлементЩо робитьСинтаксис
getterповертає значення під час читанняget prop() { ... }
setterвикликається під час присвоєнняset prop(value) { ... }
читаннявикликає getobj.prop
записвикликає setobj.prop = ...
де застосовуютьінкапсуляція, валідація, обчислювані значенняТак

Типові помилки

  • Викликати аксесор як метод. user.fullName() спричинить помилку: геттер уже повернув рядок, а рядок не є функцією.
  • Іменувати внутрішнє поле так само, як аксесор. get price() { return this.price; } дає нескінченну рекурсію і RangeError. Внутрішнє поле має називатися інакше, наприклад _price.
  • Оголошувати тільки геттер і дивуватися «мовчазному» присвоєнню. Без сеттера запис у нестрогому режимі просто ігнорується, а в 'use strict' кидає TypeError.
  • Робити геттер важким. Він виглядає як звичайне читання поля, тому виклик у циклі непомітно перетворюється на сотні обчислень. Важкі операції краще залишати звичайним методом.
  • Плутати _price з приватністю. Підкреслення це лише угода про іменування; справжню приватність дають приватні поля класів #price або замикання.
  • Забувати, що JSON.stringify() бачить геттер. Він серіалізує результат геттера як звичайне поле, тому у вихідний JSON може потрапити обчислюване значення.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.