> Какие структуры данных использовать для хранения параметров и результатов мемоизации в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Домклик
Стек: JavaScript
> Пример ответа
Короткий ответ
Для мемоизации в JavaScript чаще всего используют Map или WeakMap. Map подходит для произвольных ключей, включая объекты, и сохраняет порядок вставки. WeakMap - лучший выбор, когда ключами являются объекты, так как он не препятствует сборке мусора и предотвращает утечки памяти. Для простых случаев с примитивными аргументами можно использовать обычный объект или Map с ключами-строками. Для функций с несколькими аргументами - вложенные Map или сериализацию аргументов в строку.
Подробное объяснение
Выбор структуры данных зависит от типа ключей и жизненного цикла данных:
- Обычный объект (
{}) - подходит для примитивных ключей (строки, числа). Недостатки: прототипное наследование может привести к коллизиям (например, ключ"constructor"), и нет гарантии порядка ключей. Требует преобразования ключей в строку. Map- универсальный выбор. Принимает любые значения как ключи (объекты, функции, примитивы), сохраняет порядок вставки, имеет удобные методы (has,get,set,delete). Итерация по ключам проще, чем у объекта.WeakMap- ключи только объекты (не примитивы). Главное преимущество - слабые ссылки: если на объект-ключ нет других ссылок, запись удаляется сборщиком мусора. Это критично для мемоизации, когда ключи - временные объекты (например, аргументы-объекты в рекурсивных вызовах).- Вложенные структуры - для функций с несколькими аргументами можно использовать
MapвнутриMap(по одному уровню на аргумент). Это избегает сериализации и сохраняет ссылочную идентичность объектов. - Сериализация в строку -
JSON.stringifyили кастомный хэш для комбинации аргументов. Быстро для простых примитивов, но не работает для объектов с циклическими ссылками и теряет ссылочную идентичность (два разных объекта с одинаковым содержимым будут считаться одним ключом).
Для кэширования с ограничением размера (LRU-кэш) Map удобен, так как порядок вставки позволяет легко удалять самые старые записи.
На практике
Для типичной мемоизации функции с одним аргументом-объектом - WeakMap. Для функции с примитивными аргументами - Map с ключом-строкой или числом. Для нескольких аргументов - либо вложенные Map, либо сериализация, если аргументы примитивные и их немного. Если кэш должен жить долго и ключи - объекты, WeakMap обязателен, иначе память будет расти бесконечно.
Пример кода
JAVASCRIPT// Мемоизация с одним объектным аргументомfunction memoizeWeak(fn) {const cache = new WeakMap();return function(obj) {if (cache.has(obj)) return cache.get(obj);const result = fn(obj);cache.set(obj, result);return result;};}// Мемоизация с несколькими примитивными аргументами через Mapfunction memoizePrimitive(fn) {const cache = new Map();return function(...args) {const key = args.join('|');if (cache.has(key)) return cache.get(key);const result = fn(...args);cache.set(key, result);return result;};}// Мемоизация с несколькими объектными аргументами через вложенные Mapfunction memoizeNested(fn) {const cache = new Map();return function(...args) {let current = cache;for (let i = 0; i < args.length - 1; i++) {if (!current.has(args[i])) current.set(args[i], new Map());current = current.get(args[i]);}const lastKey = args[args.length - 1];if (current.has(lastKey)) return current.get(lastKey);const result = fn(...args);current.set(lastKey, result);return result;};}
Как отвечать на собеседовании
Начните с главного: для мемоизации ключевой выбор - между Map и WeakMap. Объясните, что WeakMap решает проблему утечек памяти для объектных ключей. Упомяните ограничение WeakMap - только объекты. Затем добавьте про Map для примитивов и про вложенные структуры для множественных аргументов. Если спросят про производительность, отметьте, что Map быстрее объекта при частых операциях добавления/удаления. Приведите пример с рекурсивной функцией (например, вычисление чисел Фибоначчи), где WeakMap спасает от накопления мусора.
Что проверяет интервьюер
Интервьюер оценивает понимание:
- различий между
Map,WeakMapи обычным объектом; - механизма сборки мусора и слабых ссылок;
- trade-off между сериализацией и сохранением ссылочной идентичности;
- умения выбирать структуру под конкретный сценарий (тип ключей, время жизни кэша);
- знания ограничений (например,
WeakMapне итерируем, нетsize).
Типичные ошибки
- Использование обычного объекта без проверки
hasOwnProperty- коллизии с прототипом. - Применение
WeakMapдля примитивных ключей - это вызовет ошибку. - Игнорирование утечек памяти:
Mapс объектными ключами без удаления записей. - Сериализация через
JSON.stringifyдля объектов - потеря идентичности и проблемы с циклическими ссылками. - Неучёт того, что
WeakMapне имеет методовsize,clearи не итерируется - это ограничивает его использование для LRU-кэша.
> Похожие задачи по frontend
Что такое метод filter в JavaScript и как он работает
Что такое JSON
Почему в JavaScript переменная, объявленная через var, всплывает и инициализируется значением undefined?
Как различать и отличать action в Redux?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью