> Как сравнить массивы аргументов для кеширования в функции memo в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: IT-One, 1221 Systems, Яндекс
Стек: JavaScript
> Пример ответа
Короткий ответ
Для сравнения массивов аргументов в memo-функции нужно использовать глубокое сравнение, так как ссылочное сравнение (===) не работает для массивов. Основные подходы: JSON.stringify (простой, но с ограничениями), рекурсивное сравнение элементов, или библиотеки вроде lodash.isEqual. Выбор зависит от требований к производительности и типов данных в аргументах.
Подробное объяснение
Кеширование результатов функций (memoization) требует сравнения предыдущих и текущих аргументов, чтобы определить, нужно ли пересчитывать результат. Для примитивных типов достаточно строгого сравнения (===), но массивы - это объекты, и сравнение по ссылке не подходит: два массива с одинаковыми элементами будут считаться разными.
Основные стратегии сравнения массивов аргументов:
-
Сериализация через JSON.stringify - преобразует массив в строку, которая используется как ключ кеша. Просто, но не работает с функциями, undefined, Symbol, циклическими ссылками, и порядок ключей в объектах может влиять на результат.
-
Рекурсивное поэлементное сравнение - обходит каждый элемент массива и сравнивает их рекурсивно. Более точное, но может быть медленным для глубоко вложенных структур.
-
Использование библиотек - lodash.isEqual или fast-deep-equal предоставляют оптимизированное глубокое сравнение.
-
Хэширование аргументов - создание уникального хэша (например, через hash-sum или собственный алгоритм) для быстрого поиска в Map.
Trade-off: JSON.stringify быстрее для простых данных, но может давать ложные совпадения при разных порядках ключей объекта. Рекурсивное сравнение точнее, но медленнее для больших массивов.
На практике
В реальных проектах для memo-функций часто используют комбинацию подходов. Для простых случаев с примитивными аргументами достаточно JSON.stringify. Если аргументы включают объекты или функции, лучше использовать библиотеку вроде lodash.isEqual или написать кастомное сравнение с учетом специфики данных.
Важно учитывать, что memoization с глубоким сравнением аргументов может быть дороже, чем сам вычисляемый результат. Поэтому такой подход оправдан только для тяжелых вычислений.
Пример кода
JAVASCRIPT// Простая memo-функция с JSON.stringifyfunction memo(fn) {const cache = new Map();return function(...args) {const key = JSON.stringify(args);if (cache.has(key)) {return cache.get(key);}const result = fn.apply(this, args);cache.set(key, result);return result;};}// Более надежная версия с глубоким сравнениемfunction memoDeep(fn) {const cache = [];return function(...args) {const entry = cache.find(([cachedArgs]) =>cachedArgs.length === args.length &&cachedArgs.every((arg, i) => deepEqual(arg, args[i])));if (entry) return entry[1];const result = fn.apply(this, args);cache.push([args, result]);return result;};}// Вспомогательная функция глубокого сравненияfunction deepEqual(a, b) {if (a === b) return true;if (typeof a !== typeof b) return false;if (Array.isArray(a) && Array.isArray(b)) {return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));}if (a && typeof a === 'object' && b && typeof b === 'object') {const keysA = Object.keys(a);const keysB = Object.keys(b);return keysA.length === keysB.length && keysA.every(k => deepEqual(a[k], b[k]));}return false;}
Как отвечать на собеседовании
Начни с объяснения проблемы: массивы - ссылочный тип, поэтому прямое сравнение не работает. Затем перечисли основные подходы с их плюсами и минусами. Упомяни, что выбор зависит от конкретных данных: для примитивов подойдет JSON.stringify, для сложных структур - глубокое сравнение. Покажи понимание trade-off между производительностью и точностью. Если спросят про оптимизацию, можно упомянуть использование WeakMap для объектов или ограничение размера кеша.
Что проверяет интервьюер
Интервьюер оценивает понимание ссылочных типов в JavaScript, знание механизмов сравнения, умение выбирать подходящий инструмент под задачу. Также проверяется способность рассуждать о производительности и edge cases (циклические ссылки, функции, undefined). Важно показать, что ты не просто знаешь JSON.stringify, а понимаешь его ограничения.
Типичные ошибки
- Использование только JSON.stringify без учета его ограничений (не работает с undefined, функциями, Symbol).
- Сравнение массивов через arr1 === arr2, что всегда false для разных массивов с одинаковым содержимым.
- Игнорирование производительности: глубокое сравнение на каждый вызов может быть дороже самого вычисления.
- Неучет контекста (this) при создании memo-функции.
- Хранение всех результатов без ограничения размера кеша, что приводит к утечке памяти.
> Похожие задачи по frontend
Почему новый объект не изменяет исходный объект при передаче в функцию в JavaScript
Можно ли сравнить два объекта в JavaScript и как это сделать
В чем разница между Promise.all и Promise.allSettled в JavaScript?
Можно ли изменять массивы и объекты, объявленные через const в JavaScript?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью