Memoize: примеры (JAVASCRIPT)
memoize(fn (function)): functionОсновы функции memoize
Мемоизация — это техника оптимизации, которая ускоряет работу функций путем кэширования результатов их вызовов. Когда функция с одинаковыми аргументами вызывается повторно, вместо выполнения вычислений возвращается сохраненный результат.
Функция memoize обычно принимает два параметра: исходную функцию для мемоизации и опциональную функцию преобразования аргументов в ключ кэша. Возвращает она новую функцию с тем же поведением, но с кэшированием результатов.
Использование мемоизации эффективно для функций с дорогостоящими вычислениями, детерминированных и часто вызываемых с одними и теми же аргументами.
Примеры использования
Простая реализация мемоизации:
function memoize(func) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = func.apply(this, args);
cache.set(key, result);
return result;
};
}
const factorial = memoize(function(n) {
return n <= 1 ? 1 : n * factorial(n - 1);
});console.log(factorial(5)); // 120 (вычислено) console.log(factorial(5)); // 120 (из кэша)
Альтернативные подходы в JavaScript
Для мемоизации можно использовать библиотеки. Lodash предоставляет функцию _.memoize с настройкой ключа кэширования. В React применяют хук useMemo для мемоизации значений и useCallback для функций. Web Workers позволяют выполнять тяжелые вычисления в отдельном потоке.
Выбор зависит от контекста: для общих функций подходит _.memoize, в React-компонентах — useMemo, для параллельных вычислений — Web Workers.
Мемоизация в других языках
В Python используют декоратор @lru_cache из модуля functools:
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)print(fibonacci(10)) # 55
В PHP мемоизацию реализуют через сохранение в массивы или кэширование в APC. В C++ применяют шаблоны для вычислений на этапе компиляции.
Типичные ошибки
Использование мемоизации с недетерминированными функциями приводит к некорректным данным:
const getRandom = memoize(() => Math.random());
console.log(getRandom()); // 0.123
console.log(getRandom()); // 0.123 (ожидается новое число)Проблемы с преобразованием ключа для сложных объектов:
const func = memoize((obj) => obj.value);
console.log(func({value: 1})); // 1
console.log(func({value: 1})); // undefined (разные ссылки объектов)Изменения в реализации
Стандарт JavaScript не включает встроенную функцию memoize, но современные реализации используют WeakMap для хранения кэша, что позволяет избежать утечек памяти. Библиотека Lodash обновляла алгоритм генерации ключа кэша для обработки разнотипных аргументов.
Расширенные примеры
Мемоизация с пользовательской функцией ключа:
function memoizeWithKey(func, keyGenerator) {
const cache = new Map();
return function(...args) {
const key = keyGenerator(...args);
if (cache.has(key)) {
return cache.get(key);
}
const result = func.apply(this, args);
cache.set(key, result);
return result;
};
}
const sum = memoizeWithKey(
(a, b) => a + b,
(a, b) => `${a}-${b}`
);console.log(sum(1, 2)); // 3 console.log(sum(1, 2)); // 3 (из кэша)
Мемоизация асинхронных функций:
async function memoizeAsync(func) {
const cache = new Map();
return async function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = await func.apply(this, args);
cache.set(key, result);
return result;
};
}