Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Властивості тільки для читання». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Властивість «тільки для читання» задають через `Object.defineProperty()` з `writable: false`, а щоб її не можна було ще й видалити чи перевизначити, додають `configurable: false`.** Якщо треба захистити весь об'єкт одразу, використовують `Object.freeze()`; якщо потрібне обчислюване значення, достатньо оголосити getter без setter. `Object.seal()` слабший: він забороняє додавати і видаляти властивості, але значення наявних змінювати дозволяє. ```javascript Object.defineProperty(obj, 'key', { value: val, writable: false }); ``` **Ключове:** одна властивість, `defineProperty` з `writable: false`; весь об'єкт, `Object.freeze()`. У strict mode спроба запису кидає `TypeError`, у звичайному коді вона просто мовчки ігнорується.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**У 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()` і циклів.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.