Skip to main content

Властивості тільки для читання

У JavaScript властивість можна зробити «тільки для читання» (read-only), тобто такою, що її не вийде змінити, видалити чи перевизначити. Способів кілька, від точкового налаштування однієї властивості до повного замороження об'єкта.

Теорія

TL;DR

  • Object.defineProperty(obj, key, { writable: false }) робить read-only одну конкретну властивість.
  • Додатковий configurable: false забороняє ще й видалення та перевизначення дескриптора.
  • Object.freeze(obj) заморожує весь об'єкт: не змінити, не додати, не видалити.
  • Object.seal(obj) слабший: значення міняти можна, структуру об'єкта, ні.
  • Getter без setter дає обчислювану властивість тільки для читання.
  • У звичайному коді невдалий запис ігнорується мовчки, у strict mode кидає TypeError.

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

javascript
const user = {}; Object.defineProperty(user, 'name', { value: 'Alice', writable: false, // забороняє змінювати enumerable: true, // властивість буде видно при переборі configurable: false // не можна видалити або перевизначити }); console.log(user.name); // "Alice" user.name = 'Bob'; // не змінить значення console.log(user.name); // "Alice" delete user.name; // не видалить властивість console.log(user.name); // "Alice"

Object.defineProperty

Це основний спосіб задати властивість із потрібними атрибутами. writable: false робить її тільки для читання, а configurable: false додатково забороняє видалення і повторне перевизначення через defineProperty.

Перевірити атрибути можна дескриптором:

javascript
console.log(Object.getOwnPropertyDescriptor(user, 'name'));

Виведе:

javascript
{ value: 'Alice', writable: false, enumerable: true, configurable: false }

Зверніть увагу: коли ви створюєте властивість через Object.defineProperty() і не вказуєте атрибути явно, вони за замовчуванням дорівнюють false. Тобто властивість і так вийде read-only, ненавмисно.

Object.freeze

Якщо треба зробити незмінними всі властивості одразу, об'єкт «заморожують»:

javascript
const user = { name: 'Alice', age: 25 }; Object.freeze(user); user.name = 'Bob'; // не змінить значення user.city = 'Kyiv'; // не додасть нову властивість delete user.age; // не видалить наявну console.log(user); // { name: 'Alice', age: 25 }

Object.freeze() робить дві речі:

  • усі наявні властивості отримують writable: false і configurable: false;
  • об'єкт стає нерозширюваним, нові властивості додати не можна.

Заморожування поверхневе: вкладені об'єкти залишаються змінюваними, і user.profile.city = 'Lviv' спрацює. Для глибокого замороження дескриптори доводиться обходити рекурсивно.

Getter без setter

Якщо значення обчислюване, окремий дескриптор не потрібен: властивість з get, але без set, автоматично стає тільки для читання.

javascript
const user = { firstName: 'Alice', lastName: 'Smith', get fullName() { return `${this.firstName} ${this.lastName}`; } }; console.log(user.fullName); // "Alice Smith" user.fullName = 'Bob Jones'; // не спрацює

Object.seal

Коли повне замороження надмірне, а треба лише зафіксувати структуру об'єкта:

javascript
const user = { name: 'Alice' }; Object.seal(user); user.name = 'Bob'; // можна змінити delete user.name; // не можна видалити user.age = 30; // не можна додати

На відміну від freeze(), seal() дозволяє міняти значення наявних властивостей, але забороняє змінювати склад об'єкта.

Порівняння способів

СпосібЩо робитьЗмінити значенняДодати або видалити
Object.defineProperty(obj, key, { writable: false })Робить конкретну властивість read-onlyНіТак
Object.freeze(obj)Заморожує весь об'єктНіНі
Object.seal(obj)Забороняє додавати і видаляти властивостіТакНі
Getter без setterОбчислювана властивість тільки для читанняНіТак

Коротко: щоб зробити властивість тільки для читання, використовуйте Object.defineProperty(obj, 'key', { value: val, writable: false }), або заморозьте весь об'єкт через Object.freeze(obj).

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

  • Чекати на виняток у звичайному коді. Поза strict mode присвоєння read-only властивості просто нічого не робить, помилки не буде. Тому баг легко не помітити: у модулях і класах, де strict mode увімкнено завжди, той самий код кине TypeError.
  • Плутати freeze і seal. seal() не робить властивості read-only, він лише фіксує набір ключів.
  • Вважати Object.freeze() глибоким. Вкладені об'єкти і масиви після замороження батька змінюються вільно.
  • Забувати про configurable: false. З writable: false, але configurable: true властивість можна перевизначити повторним викликом Object.defineProperty() і так обійти захист.
  • Не вказувати атрибути явно. У Object.defineProperty() пропущені writable, enumerable і configurable дорівнюють false, тож властивість може несподівано зникнути з Object.keys() і циклів.

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

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

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