Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Map vs Object: почему ключи-объекты становятся [object Object] и крашат кэш сессий

Map vs Object: почему ключи-объекты становятся [object Object] и крашат кэш сессий

Запланировано Прикреплена Закрыта Перенесена JavaScript
mapobjectкэш сессий
1 Сообщения 1 Постеры 1 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH Не в сети
    hannadevH Не в сети
    hannadev
    написал отредактировано
    #1

    Map и Object кажутся похожими, но ключи-объекты в Object превращаются в “[object Object]” и затирают данные. Это бьет по кэшу сессий, когда userId как объект улетает в никуда. Разберем под капотом, почему так происходит и как фиксить без костылей.

    В сессионном кэше часто хранят данные по объектным ключам - типа {userId: {data}}. Object их строкует, и разные объекты сливаются в одну строку. Map держит ссылки как есть. Это спасает от коллизий в реальных проектах с авторизацией и state.

    Как Object ломает ключи-объекты

    Object в JS - это не коллекция, а хэш-таблица со строковыми ключами. Любое значение, не строка или Symbol, преобразуется через toString(). Объект по умолчанию дает “[object Object]”, функция - “function …()”. Поэтому два разных userId-объекта сливаются в одну запись.

    Представь кэш сессий: генеришь уникальный объект для пользователя, кладешь данные. Следующий запрос - новый объект, но ключ строкует в то же “[object Object]”. Старые данные перезаписываются. Краш: сессия теряет состояние, пользователь видит чужие данные или пустоту.

    Вот классическая засада:

    • Создаешь const cache = {};
    • const user1 = {id: 123}; cache[user1] = 'session1';
    • const user2 = {id: 123}; cache[user2] = 'session2';
    • console.log(cache[user1]); // 'session2' - коллизия!

    Реальный пример из сессий:

    const sessionCache = {};
    function getSession(userObj) {
      return sessionCache[userObj] || 'new';
    }
    const u1 = {id: 1};
    const u2 = {id: 1};
    sessionCache[u1] = 'user1 data';
    console.log(getSession(u2)); // 'user1 data' - но должно быть undefined
    

    Нюанс: Даже если объекты “равны” по содержимому, ссылки разные - Object их не различает после toString().

    Map держит ссылки без принуждения

    Map - настоящая коллекция ключ-значение без строкования. Ключ остается объектом, сравнивается по ссылке через ===. Размер через .size, итерация через for…of. Идеально для динамических ключей в кэше.

    В сессиях: генерируешь объект-ключ один раз на userId, держишь в Map. Последующие запросы используют тот же объект или WeakMap для GC. Нет коллизий, производительность на частых set/get выше Object при >100 записях.

    Перепишем кэш:

    const sessionCache = new Map();
    const u1 = {id: 1};
    const u2 = {id: 1};
    sessionCache.set(u1, 'user1 data');
    console.log(sessionCache.get(u2)); // undefined - ок!
    console.log(sessionCache.size); // 1
    

    Преимущества Map для кэша сессий:

    • Ключи любого типа: объекты, функции, Date.
    • .has(key), .delete(key) - O(1) без Object.keys().
    • Итераторы keys(), values(), entries() - чище Object.entries().
    Свойство Object Map
    Ключи строки/Symbol любой тип
    Размер Object.keys().length .size
    Get/Set obj[key] .get/.set
    Итерация for…in (прототип!) for…of чисто
    Кэш сессий коллизии [object Object] ссылки OK

    WeakMap для сессий без утечек памяти

    Обычный Map держит ключи сильно, объект-ключ не удалится GC пока Map жив. Для сессий - WeakMap: ключи слабо ссылаются, память чистится автоматически при удалении userObj.

    В бэкенде/фронте: хранишь сессию по DOM-элементу или Worker’у как ключ. Когда элемент удален - сессия уходит без .delete. Идеально для временного кэша без ручной уборки.

    Практика:

    const sessionWeakCache = new WeakMap();
    const userObj = {id: 1};
    sessionWeakCache.set(userObj, 'session data');
    console.log(sessionWeakCache.get(userObj)); // 'session data'
    // userObj = null; // ключ удалится GC
    

    Когда WeakMap рулит:

    • Ключи - DOM-ноды, объекты от API без ID.
    • Нет .size, .keys() - только get/set/has/delete.
    • Нет сериализации в JSON - только для runtime кэша.

    Подводный камень: WeakMap не итерируется, нельзя Object.fromEntries(map).

    Фиксим legacy-код: от Object к Map

    В старом коде cache на Object. Миграция: new Map(Object.entries(cacheOld)), но только если ключи строковые! Для объектных - рефактори ключ на stringId или Symbol.

    Гибрид: публичный API оставь Object, внутри Map. Конвертируй через Object.fromEntries(map.entries()) - но проверяй ключи на объекты.

    Шаги рефакторинга:

    1. Замени const cache = {} на new Map().
    2. .set(key, val) вместо cache[key] = val.
    3. .get(key) вместо cache[key]. Добавь || default.
    4. Для JSON - Object.fromEntries(cache).

    Антипаттерны избегать:

    • JSON.stringify(key) как хэш - коллизии по содержимому.
    • Массивы как ключи в Object - то же [object Array].
    • Глобальный cache без WeakMap - утечки памяти.

    Под капотом еще есть грабли

    Object прототип наследуется, Map чистый. В Object for…in ловит Object.prototype - фильтруй hasOwnProperty. Map итерируется только свои записи.

    Осталось: производительность на 10k+ элементов (Map быстрее), полифиллы для старых браузеров. Подумай, стоит ли WeakRef в связке с Map для продвинутого GC в сессиях - там свои подводные камни с timing’ом очистки.

    1 ответ Последний ответ
    0

    Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.

    Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.

    С вашими комментариями этот пост мог бы стать ещё лучше 💗

    Зарегистрироваться Войти

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com

    © 2024 - 2026 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы