Object.freeze и Object.seal в JS

c033f0d6903664b38e8e4c8c51c8f948.png

Привет, Хабр!

Сегодня рассмотрим такие инструменты в JS, как Object.freeze и Object.seal. С помощью них можно установить надежный контроль над объектами, защитив их от нежелательных изменений.

Как работают Object.freeze и Object.seal

Object.freeze

Object.freeze предотвращает любые изменения объекта. Это означает, что вы не сможете:

  • Добавлять новые свойства.

  • Удалять существующие свойства.

  • Изменять значения уже существующих свойств.

Посмотрим на пример:

const user = {
    name: "Artem",
    age: 30
};

Object.freeze(user);

// Попытка изменить существующее свойство
user.age = 31; // Без изменений

// Попытка добавить новое свойство
user.email = "alice@example.com"; // Без изменений

console.log(user); // { name: "Artem", age: 30 }

Как вы видите, все попытки изменить объект не сработали. На низком уровне Object.freeze добавляет флаг non-configurable ко всем свойствам объекта, что не позволяет их изменять.

Если есть вложенные объекты, Object.freeze не замораживает их автоматически. Т.е вложенные свойства все еще могут быть изменены:

const nestedUser = {
    name: "Ivan",
    address: {
        city: "New York"
    }
};

Object.freeze(nestedUser);

nestedUser.address.city = "Los Angeles"; // Изменение возможно!

console.log(nestedUser.address.city); // "Los Angeles"

Чтобы заморозить вложенные объекты, придется делать это вручную или написать рекурсивную функцию.

Object.seal

Object.seal позволяет вам запечатать объект, что предотвращает добавление или удаление свойств, но не мешает изменению значений существующих свойств.

Посмотрим на примере:

const settings = {
    theme: "light",
    notifications: true
};

Object.seal(settings);

// Попытка изменить существующее свойство
settings.theme = "dark"; // Изменение успешно

// Попытка добавить новое свойство
settings.language = "en"; // Без изменений

// Попытка удалить свойство
delete settings.notifications; // Без изменений

console.log(settings); // { theme: "dark", notifications: true }

Изменение theme прошло успешно, но мы не получилось ни добавить новое свойство, ни удалить существующее.

Примеры использования

Защита конфигурационных объектов

Конфигурационные объекты — это те сущности, которые задают поведение вашего приложения. Они должны быть стабильными и неизменными, чтобы избежать случайных ошибок:

const config = {
    apiUrl: "https://api.example.com",
    timeout: 5000,
    retries: 3
};

Object.freeze(config);

// Функция для получения конфигурации
function getConfig() {
    return config;
}

// Пример использования
console.log(getConfig().apiUrl); // "https://api.example.com"

// Попытка изменить конфигурацию
config.apiUrl = "https://api.changed.com"; // Не сработает
console.log(getConfig().apiUrl); // Все еще "https://api.example.com"

Используя Object.freeze, мы гарантируем, что любые попытки изменить config будут игнорироваться/

Использование в библиотеке Redux

В Redux иммутабельность состояния — ключ к предсказуемости и простоте отладки. Путем использования Object.freeze, можно защитить состояние от нежелательных мутаций.

Пример:

const initialState = {
    user: null,
    loggedIn: false
};

function reducer(state = initialState, action) {
    switch (action.type) {
        case 'LOGIN':
            return Object.freeze({
                ...state,
                user: action.payload,
                loggedIn: true
            });
        case 'LOGOUT':
            return Object.freeze(initialState);
        default:
            return state;
    }
}

Здесь \используем Object.freeze, чтобы убедиться, что каждый раз, когда состояние обновляется, оно остается неизменным.

Пример с React

В React часто возникает необходимость управлять состоянием компонентов. Защита состояния с помощью Object.freeze может помочь предотвратить ошибки при мутациях данных.

Пример:

import React, { useState } from 'react';

const App = () => {
    const [config, setConfig] = useState(Object.freeze({
        theme: 'light',
        notificationsEnabled: true
    }));

    const toggleTheme = () => {
        // Создаем новый объект вместо изменения существующего
        setConfig(prevConfig => Object.freeze({
            ...prevConfig,
            theme: prevConfig.theme === 'light' ? 'dark' : 'light'
        }));
    };

    return (
        

Текущая тема: {config.theme}

); }; export default App;

В этом примере мы используем Object.freeze, чтобы защитить состояние конфигурации.

Защита констант и глобальных переменных

Когда вы работаете с константами, иногда приходится гарантировать, что эти значения не будут случайно изменены. СObject.freeze можно сделать константы действительно неизменными.

Пример:

const constants = Object.freeze({
    MAX_CONNECTIONS: 100,
    DEFAULT_TIMEOUT: 3000,
    APP_NAME: "MyApp"
});

// Попытка изменить константу
constants.MAX_CONNECTIONS = 200; // Не сработает

console.log(constants.MAX_CONNECTIONS); // 100

В этом примере, даже если кто-то попытается изменить MAX_CONNECTIONS, изменение не произойдет, и ваше приложение останется стабильным.

Больше про языки программирования эксперты OTUS рассказывают в рамках практических онлайн-курсов. С полным каталогом курсов можно ознакомиться по ссылке.

Habrahabr.ru прочитано 968 раз