/** * @function memoize * @description -> * From [Wikipedia](https://en.wikipedia.org/wiki/Memoization), * memoization is an optimization technique * used primarily to speed up computer programs, * by storing the results of expensive function calls * and returning the cached result when the same inputs occur again * This function is a first class objects, * which lets us use it as [Higher-Order Function](https://eloquentjavascript.net/05_higher_order.html) * and return another function * @param {Function} func Original function * @param {Map} cache - it's receive any cache DS which have get, set & has method * @returns {Function} Memoized function */ const memoize = (func, cache = new Map()) => { const jsonReplacer = (_, value) => { if (value instanceof Set) { // if the value is Set it's converted to Array cause JSON.stringify can't convert Set return [...value] } if (value instanceof Map) { // if the value is Map it's converted to Object cause JSON.stringify can't convert Map return Object.fromEntries(value) } return value } return (...args) => { /** * Arguments converted to JSON string for use as a key of Map - it's easy to detect collections like -> Object and Array * If the args input is -> [new Set([1, 2, 3, 4]), {name: 'myName', age: 23}] * Then the argsKey generate to -> '[[1,2,3,4],{"name":"myName","age":23}]' which is JSON mean string * Now it's ready to be a perfect key for Map */ const argsKey = JSON.stringify(args, jsonReplacer) /** * Checks if the argument is already present in the cache, * then return the associated value / result */ if (cache.has(argsKey)) { return cache.get(argsKey) } /** * If the argument is not yet present in the cache, * execute original function and save its value / result in cache, * finally return it */ const result = func(...args) // spread all args cache.set(argsKey, result) return result } } export { memoize }