Object.freeze() у JavaScript
Object.freeze() це вбудований метод JavaScript, який «заморожує» об'єкт і робить його повністю незмінним: властивості не можна змінити, видалити або додати. Метод повертає той самий об'єкт, а не його копію, і діє лише на верхній рівень структури.
Теорія
TL;DR
Object.freeze(obj)робить об'єкт незмінним і повертає той самий об'єкт.- Не можна перезаписати, додати або видалити властивості.
- Не можна змінити дескриптори
configurableіwritable. - Перевірка стану:
Object.isFrozen(obj). - Заморозка поверхнева (shallow): вкладені об'єкти лишаються змінюваними.
Object.seal()забороняє додавання і видалення, але дозволяє змінювати значення;Object.preventExtensions()забороняє лише додавання нових властивостей.
Швидкий приклад
const user = {
name: 'Alice',
age: 25
};
Object.freeze(user);
user.name = 'Oleh'; // не змінить
user.city = 'Kyiv'; // не можна додати нове
delete user.age; // не можна видалити
console.log(user); // { name: 'Alice', age: 25 }Синтаксис і перевірка стану
Object.freeze(obj)| Аргумент | Опис |
|---|---|
obj | Об'єкт, який потрібно «заморозити» |
Метод повертає той самий об'єкт, але вже із замороженими властивостями, тому запис const frozen = Object.freeze(user) дає не копію, а друге ім'я для user.
Після Object.freeze() об'єкт стає незмінним:
- властивості не можна перезаписати;
- не можна видалити або додати нові;
- не можна поміняти
configurableабоwritable.
Перевірити стан можна окремим методом:
console.log(Object.isFrozen(user)); // trueВарто пам’ятати про режим виконання: у звичайному (нестрогому) коді спроба запису просто мовчки ігнорується, а в 'use strict' або всередині ES-модуля вона кидає TypeError. Саме тому баг легко не помітити в старому скрипті і одразу побачити в сучасному модулі.
Заморозка поверхнева (shallow)
Якщо всередині є вкладені об'єкти, вони лишаються змінюваними:
const user = {
name: 'Alice',
address: {
city: 'Kyiv'
}
};
Object.freeze(user);
user.address.city = 'Lviv'; // працює
console.log(user.address.city); // "Lviv"Тобто Object.freeze() захищає тільки верхній рівень. Заморожено саме посилання на address: замінити його іншим об'єктом не можна, а от змінити щось усередині того самого об'єкта, будь ласка. Для «глибокої» заморозки потрібно заморожувати рекурсивно.
Глибока заморозка (deep freeze)
function deepFreeze(obj) {
Object.freeze(obj);
for (const key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null && !Object.isFrozen(obj[key])) {
deepFreeze(obj[key]);
}
}
return obj;
}
const user = {
name: 'Alice',
address: { city: 'Kyiv' }
};
deepFreeze(user);
user.address.city = 'Lviv'; // не змінить
console.log(user.address.city); // "Kyiv"Тепер об'єкт і весь його вміст повністю «заморожені». Перевірка !Object.isFrozen(obj[key]) потрібна не лише для швидкості: без неї циклічне посилання (a.self = a) призвело б до нескінченної рекурсії.
freeze, seal і preventExtensions
| Метод | Що робить | Можна міняти значення | Можна додавати або видаляти властивості |
|---|---|---|---|
Object.freeze() | Повністю заморожує | Ні | Ні |
Object.seal() | Забороняє додавання і видалення, але дозволяє міняти значення | Так | Ні |
Object.preventExtensions() | Забороняє додавання нових властивостей | Так | Додавати не можна, старі видаляти можна |
Приклад freeze проти seal:
const user = { name: 'Alice' };
Object.seal(user);
user.name = 'Oleh'; // можна
delete user.name; // не можна
Object.freeze(user);
user.name = 'Max'; // не можнаПідсумкова таблиця:
| Властивість | Поведінка |
|---|---|
Object.freeze() | робить об'єкт повністю незмінним |
| Заборонено | додавати, видаляти або змінювати властивості |
| Працює поверхнево | вкладені об'єкти лишаються змінюваними |
| Перевірка | Object.isFrozen(obj) |
Типові помилки
- Вважати, що заморожено весь граф об'єктів.
Object.freeze()захищає лише верхній рівень; масив усередині замороженого об'єкта спокійно приймаєpush(). - Розраховувати на помилку при записі. У нестрогому режимі присвоєння до замороженої властивості мовчки нічого не робить, тому баг живе непоміченим до переходу на модулі або
'use strict'. - Плутати
freezeіseal.Object.seal()фіксує лише набір ключів, значення наявних властивостей змінювати можна. - Думати, що метод повертає копію. Він повертає той самий об'єкт, тож усі старі посилання теж стають замороженими.
- Морозити об'єкт, який потім треба оновлювати. Для стану додатка краще створювати новий об'єкт (
{ ...state, city: 'Lviv' }), а не намагатися мутувати заморожений. - Забувати про циклічні посилання в
deepFreeze(). Без перевіркиObject.isFrozen()рекурсія зациклюється і падає зі стеком.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.