Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает Object.freeze() в JavaScript
Object.freeze() - это метод, который делает объект неизменяемым. Он предотвращает добавление, удаление и изменение свойств объекта. Это важный инструмент для обеспечения immutability в функциональном программировании.
1. Базовое использование
const user = {
name: 'Alice',
age: 30,
email: 'alice@example.com'
};
// Заморозить объект
Object.freeze(user);
// Попытка изменения - молча не срабатывает (в strict mode выбросит ошибку)
user.age = 31; // Не изменится
user.name = 'Bob'; // Не изменится
// Попытка добавления нового свойства
user.phone = '123456'; // Не добавится
// Попытка удаления
delete user.email; // Не удалится
console.log(user); // { name: 'Alice', age: 30, email: 'alice@example.com' }
// Проверка, заморожен ли объект
console.log(Object.isFrozen(user)); // true
2. Strict Mode и Object.freeze
'use strict';
const obj = { count: 0 };
Object.freeze(obj);
try {
obj.count = 1; // TypeError: Cannot assign to read only property 'count'
} catch (e) {
console.error(e.message);
}
Без strict mode ошибок нет, но присваивание не срабатывает (молчаливо игнорируется).
3. Глубокое замораживание (Deep Freeze)
Обратите внимание: Object.freeze() замораживает только первый уровень:
const user = {
name: 'Alice',
address: {
city: 'New York',
country: 'USA'
}
};
Object.freeze(user);
// Это не сработает
user.address = { city: 'London', country: 'UK' };
// Но это сработает! Вложенный объект не заморожен
user.address.city = 'London';
console.log(user); // { name: 'Alice', address: { city: 'London', country: 'UK' } }
// Функция для глубокого замораживания
function deepFreeze(obj) {
Object.freeze(obj);
Object.getOwnPropertyNames(obj).forEach(prop => {
if (obj[prop] !== null &&
(typeof obj[prop] === 'object' || typeof obj[prop] === 'function') &&
!Object.isFrozen(obj[prop])) {
deepFreeze(obj[prop]);
}
});
return obj;
}
const safeUser = deepFreeze(user);
user.address.city = 'Paris'; // Теперь это не сработает
4. Object.freeze vs Object.seal vs Object.preventExtensions
// 1. Object.freeze() - не можно менять, добавлять, удалять
const frozen = { a: 1 };
Object.freeze(frozen);
frozen.a = 2; // Ошибка
frozen.b = 3; // Ошибка
delete frozen.a; // Ошибка
// 2. Object.seal() - можно менять, но не добавлять/удалять
const sealed = { a: 1 };
Object.seal(sealed);
sealed.a = 2; // OK
sealed.b = 3; // Ошибка
delete sealed.a; // Ошибка
// 3. Object.preventExtensions() - можно менять/удалять, но не добавлять
const extended = { a: 1 };
Object.preventExtensions(extended);
extended.a = 2; // OK
extended.b = 3; // Ошибка
delete extended.a; // OK
// Таблица:
// Операция | freeze | seal | preventExtensions
// Изменение | Нет | Да | Да
// Добавление | Нет | Нет | Нет
// Удаление | Нет | Нет | Да
5. React и Object.freeze для оптимизации
import { useMemo } from 'react';
function UserList({ users }) {
// Object.freeze помогает React оптимизировать
const frozenUsers = useMemo(() => {
return Object.freeze(users);
}, [users]);
return (
<ul>
{frozenUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// Freeze для constants
const API_ENDPOINTS = Object.freeze({
users: '/api/users',
posts: '/api/posts',
comments: '/api/comments'
});
// Попытка изменить не сработает
API_ENDPOINTS.users = '/api/modified'; // Игнорируется
6. Object.freeze для защиты конфигурации
const config = Object.freeze({
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3,
features: Object.freeze({
darkMode: true,
notifications: true
})
});
// Ошибка при попытке изменения
config.timeout = 10000; // Молчаливо игнорируется
// Правильный способ - создать новый объект
const newConfig = {
...config,
timeout: 10000
};
// Или для вложенных
const newConfig2 = {
...config,
features: {
...config.features,
darkMode: false
}
};
7. Object.freeze vs const
// const предотвращает переприсваивание переменной
const obj = { count: 0 };
obj = { count: 1 }; // TypeError: obj is read-only
// Но не предотвращает изменение свойств
obj.count = 1; // OK
// Object.freeze предотвращает изменение свойств
const frozen = { count: 0 };
frozen.count = 1; // Не срабатывает
// Комбо: const + Object.freeze = максимальная защита
const config = Object.freeze({
app: 'MyApp',
version: '1.0.0'
});
config.app = 'NewApp'; // Не срабатывает
config = {}; // TypeError: config is read-only
8. Проверка свойств замороженного объекта
const user = { name: 'Alice', age: 30 };
Object.freeze(user);
// Получение дескриптора свойства
const descriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log(descriptor);
// { value: 'Alice', writable: false, enumerable: true, configurable: false }
// Все свойства читаются
console.log(Object.getOwnPropertyNames(user)); // ['name', 'age']
// Проверка на наличие свойства
console.log('name' in user); // true
console.log(user.hasOwnProperty('name')); // true
9. Object.freeze с методами
const calculator = Object.freeze({
value: 0,
add(n) {
return calculator.value + n; // Чтение OK
},
multiply(n) {
return calculator.value * n;
}
});
// Методы работают, но не могут менять состояние
console.log(calculator.add(5)); // 5
// Это не сработает
calculator.value = 10; // Игнорируется
10. Производительность и альтернативы
// Object.freeze имеет overhead
const largeObject = Object.freeze({
// 10000 свойств
});
// Для приватных данных используй WeakMap/WeakSet
const privateData = new WeakMap();
class User {
constructor(name) {
privateData.set(this, { name });
}
getName() {
return privateData.get(this).name;
}
}
// Или используй # private fields (ES2022)
class SecureUser {
#name;
constructor(name) {
this.#name = name;
}
getName() {
return this.#name;
}
}
Ключевые моменты
- Object.freeze() делает объект неизменяемым на уровне свойств
- Замораживает только первый уровень (используй deepFreeze для вложенных)
- В strict mode выбросит TypeError при попытке изменения
- Без strict mode ошибок нет, но изменения не произойдут
- Object.isFrozen() проверяет, заморожен ли объект
- Отличается от const (const - для переменной, freeze - для объекта)
- Используй для конфигов, констант и защиты от случайного изменения
- Для более сложной инкапсуляции используй private fields (#)