Skip to main content

Як реалізувати мемоізацію функції?

1. Базова реалізація (для однієї функції з примітивними аргументами)

javascript
function memoize(fn) { const cache = {}; return function (...args) { const key = JSON.stringify(args); // створюємо ключ з аргументів if (key in cache) { console.log('Беремо з кешу:', key); return cache[key]; } console.log('Обчислюємо:', key); const result = fn(...args); cache[key] = result; return result; }; }

Приклад використання:

javascript
function slowAdd(a, b) { // імітація важких обчислень for (let i = 0; i < 1e8; i++); return a + b; } const memoAdd = memoize(slowAdd); console.log(memoAdd(2, 3)); // Обчислюємо console.log(memoAdd(2, 3)); // Беремо з кешу console.log(memoAdd(4, 5)); // Обчислюємо

Тепер повторні виклики з тими самими аргументами не перераховуються - просто беруться з пам'яті.


2. Універсальна реалізація (з Map замість об'єкта)

Краще використовувати Map, тому що він швидший і надійніший для ключів будь-якої структури.

javascript
function memoize(fn) { const cache = new Map(); return function (...args) { const key = JSON.stringify(args); if (cache.has(key)) { return cache.get(key); } const result = fn(...args); cache.set(key, result); return result; }; }

Перевага: можна безпечно кешувати значення навіть для складних аргументів (arrays, objects).


3. Просунута версія з обмеженням розміру кешу (LRU Cache)

Щоб кеш не зростав нескінченно і не "з'їдав" пам'ять.

javascript
function memoize(fn, limit = 5) { const cache = new Map(); return function (...args) { const key = JSON.stringify(args); if (cache.has(key)) { // оновлюємо порядок використання const value = cache.get(key); cache.delete(key); cache.set(key, value); return value; } const result = fn(...args); cache.set(key, result); // якщо кеш занадто великий - видаляємо найстаріший елемент if (cache.size > limit) { const oldestKey = cache.keys().next().value; cache.delete(oldestKey); } return result; }; }

Тепер кеш "ковзний": зберігає останні N викликів, що корисно для реальних застосунків.


4. Приклад реального застосування - мемоізація рекурсивної функції (фібоначчі)

javascript
function memoize(fn) { const cache = {}; return function (n) { if (n in cache) return cache[n]; const result = fn(n); cache[n] = result; return result; }; } const fib = memoize(function f(n) { if (n <= 1) return n; return f(n - 1) + f(n - 2); }); console.log(fib(40)); // Швидко, попри рекурсію

Без мемоізації це було б десятки мільйонів викликів, а з кешем - лише 40.


5. Реалізація з підтримкою асинхронних функцій

Коли потрібно кешувати результати fetch, axios, db.query тощо.

javascript
function memoizeAsync(fn) { const cache = new Map(); return async function (...args) { const key = JSON.stringify(args); if (cache.has(key)) return cache.get(key); const promise = fn(...args).then(result => { cache.set(key, result); return result; }); cache.set(key, promise); return promise; }; }

Приклад:

javascript
const fetchUser = memoizeAsync(async (id) => { const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`); return res.json(); }); await fetchUser(1); // перший раз - HTTP-запит await fetchUser(1); // другий раз - миттєво, з кешу

6. Коли і де використовувати мемоізацію

СценарійПідходить?Чому
Дорогі обчисленняТакПришвидшує повторні виклики
Повторювані аргументиТакВигода від кешу
Різні аргументи щоразуНіКеш марний
HTTP-запити, БДОбережноМожна, якщо дані рідко змінюються
Великі даніОбережноСлідкуй за пам'яттю

Резюме

Мемоізація - це кешування результатів функції, щоб пришвидшити повторні виклики. У JS реалізується через замикання, сховище (Map/Object) і серіалізацію аргументів (JSON.stringify).

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.