> Как сделать объект немутабельным в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Сбер
Стек: JavaScript
> Пример ответа
Короткий ответ
Немутабельность в JavaScript достигается комбинацией: Object.freeze() для поверхностной защиты, глубокого замораживания для вложенных структур, и иммутабельных паттернов (copy-on-write) через spread-оператор или structuredClone. Для примитивов немутабельность уже встроена. Важно помнить, что const не делает объект немутабельным - он лишь запрещает переприсваивание переменной.
Подробное объяснение
Немутабельность означает, что после создания объект нельзя изменить. В JavaScript есть несколько уровней защиты:
1. Object.freeze(obj) - делает объект нерасширяемым, свойства становятся неперезаписываемыми и неперечисляемыми. Но это поверхностная заморозка: вложенные объекты остаются мутабельными.
2. Object.seal(obj) - запрещает добавление/удаление свойств, но позволяет изменять значения существующих.
3. Object.preventExtensions(obj) - только запрещает добавление новых свойств.
4. Глубокая заморозка - рекурсивный Object.freeze() для всех вложенных объектов.
5. Иммутабельные структуры данных - библиотеки вроде Immutable.js или Immer, которые создают новые объекты при каждом изменении.
6. Паттерн copy-on-write - вместо мутации создаётся копия с изменениями через spread или structuredClone.
Для примитивов (string, number, boolean, null, undefined, symbol, bigint) немутабельность гарантирована языком - любые операции возвращают новое значение.
На практике
В реальных проектах чаще используют комбинацию подходов:
- Для конфигураций и констант -
Object.freeze()+ глубокое замораживание. - Для state-менеджмента (Redux, Zustand) - иммутабельные обновления через spread или Immer.
- Для передачи данных между потоками -
structuredCloneдля глубоких копий. - Для защиты API от случайных мутаций - TypeScript
Readonly<T>на уровне типов.
Важно: заморозка не защищает от мутаций через Proxy или Reflect.set, и не делает объект сериализуемым быстрее.
Пример кода
JAVASCRIPT// Поверхностная заморозкаconst config = Object.freeze({ apiUrl: 'https://api.example.com', retries: 3 });config.retries = 5; // не сработает в strict mode, молча проигнорируется в sloppyconsole.log(config.retries); // 3// Глубокая заморозкаfunction deepFreeze(obj) {Object.keys(obj).forEach(key => {if (typeof obj[key] === 'object' && obj[key] !== null) {deepFreeze(obj[key]);}});return Object.freeze(obj);}const settings = deepFreeze({theme: { color: 'dark', font: { size: 14 } }});settings.theme.font.size = 20; // не сработает// Иммутабельное обновление через spreadconst state = { user: { name: 'Alice', age: 30 } };const newState = {...state,user: { ...state.user, age: 31 }};// structuredClone для глубокого копированияconst original = { nested: { value: 1 } };const cloned = structuredClone(original);cloned.nested.value = 2;console.log(original.nested.value); // 1
Как отвечать на собеседовании
Начните с определения немутабельности и её важности для предсказуемости кода. Затем перечислите инструменты: Object.freeze(), Object.seal(), preventExtensions(), глубокое замораживание, иммутабельные паттерны. Обязательно упомяните ограничения: поверхностность freeze, невозможность полной защиты от Proxy, и что const - это не про немутабельность. Приведите пример из реальной практики - например, почему в Redux нельзя мутировать state. Если спросят про производительность, отметьте trade-off: иммутабельность даёт безопасность и упрощает отслеживание изменений, но требует больше памяти на копии.
Что проверяет интервьюер
Интервьюер оценивает:
- Понимание разницы между
constи немутабельностью. - Знание уровней защиты объектов (
freeze,seal,preventExtensions). - Осознание ограничений поверхностной заморозки.
- Умение применять иммутабельные паттерны на практике.
- Понимание, когда нужна глубокая заморозка, а когда достаточно copy-on-write.
- Знание современных инструментов:
structuredClone, Immer, Immutable.js.
Типичные ошибки
- Утверждение, что
constделает объект немутабельным. - Использование
Object.freeze()без учёта вложенных объектов. - Забывают, что замороженный объект всё ещё можно изменить через
Object.definePropertyсconfigurable: true(если свойство было таким до заморозки). - Путаница между
Object.freeze()иObject.seal(). - Попытка заморозить
Date,Map,Set- они не становятся полностью немутабельными черезfreeze. - Игнорирование strict mode: в sloppy mode мутация замороженного объекта молча игнорируется, что маскирует ошибки.
> Похожие задачи по frontend
Как проитерироваться по объекту в JavaScript
С каким продуктом ты работал
Как добавить элемент в документ внутри другого элемента в DOM
Можно ли явно добавить микротаск в JavaScript
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью