# Where and how can I use memoization in JavaScript?

Angelos Chalaris · JavaScript, Function, Memoization · Nov 7, 2021 Memoization is a commonly used technique that can help speed up your code significantly. This technique relies on a cache to store results for previously completed units of work. The purpose of the cache is to avoid performing the same work more than once, speeding up subsequent calls of time-consuming functions. Based on this definition, we can easily extract some criteria that can help us decide when to use memoization in our code:

• Memoization is useful mainly in speeding up slow-performing, costly or time-consuming function calls
• Memoization speeds up subsequent calls, so it's best used when you anticipate multiple calls of the same function under the same circumstances
• Memoization stores results in memory, so it should be avoided when the same function is called multiple times under very different circumstances

A simple, object-oriented example of implementing memoization could be as follows:

```class MyObject {
constructor(data) {
this.data = data;
this.data[this.data.length - 2] = { value: 'Non-empty' };
}

firstNonEmptyItem() {
return this.data.find(v => !!v.value);
}

firstNonEmptyItemMemo() {
if (!this.firstNonEmpty)
this.firstNonEmpty = this.data.find(v => !!v.value);
return this.firstNonEmpty;
}
}

const myObject = new MyObject(Array(2000).fill({ value: null }));

for (let i = 0; i < 100; i ++)
myObject.firstNonEmptyItem();       // ~4000ms
for (let i = 0; i < 100; i ++)
myObject.firstNonEmptyItemMemo();   // ~70ms```

This example showcases a way to implement memoization inside a class. However, it makes a couple of assumptions. First, it's assumed that the `data` structure will not be altered over the lifecycle of the object. Seconds, it's assumed that this is the only expensive function call we will make, so the code is not reusable. The example also doesn't account for arguments being passed to the function, which would alter the result. A functional approach would work with any given function and also account for arguments. Such an approach can be seen in the form of the memoize snippet, which uses a `Map` to store different values.

We still recommend using that snippet as the primary way to memoize a function, however JavaScript's Proxy object provides an interesting alternative via the use of the `handler.apply()` trap, which can be used for this purpose as follows:

```const memoize = fn => new Proxy(fn, {
cache: new Map(),
apply (target, thisArg, argsList) {
let cacheKey = argsList.toString();
if(!this.cache.has(cacheKey))
this.cache.set(cacheKey, target.apply(thisArg, argsList));
return this.cache.get(cacheKey);
}
});

const fibonacci = n => (n <= 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2));
const memoizedFibonacci = memoize(fibonacci);

for (let i = 0; i < 100; i ++)
fibonacci(30);                      // ~5000ms
for (let i = 0; i < 100; i ++)
memoizedFibonacci(30);              // ~50ms```

## Recommended snippets

• ### Can I use an arrow function as the callback for an event listener in JavaScript?

JavaScript, Browser

Learn the differences between JavaScript ES6 arrow functions and regular functions and how they affect event listener callbacks.

• ### Pipe async functions

JavaScript, Function

Performs left-to-right function composition for asynchronous functions.

• ### Converge branching functions

JavaScript, Function

Converges a list of branching functions into a single function and returns the result.
{"ft_lang_label":"__label__en","ft_lang_prob":0.7411374,"math_prob":0.81879616,"size":2737,"snap":"2022-40-2023-06","text_gpt3_token_len":645,"char_repetition_ratio":0.118551046,"word_repetition_ratio":0.057831325,"special_character_ratio":0.25429302,"punctuation_ratio":0.18590999,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9770387,"pos_list":[0,1,2],"im_url_duplicate_count":[null,3,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-10-06T11:00:01Z\",\"WARC-Record-ID\":\"<urn:uuid:3683ecf6-34ac-4915-aac5-e5fbafba07f2>\",\"Content-Length\":\"51758\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:aae97185-1f05-450b-9495-0f2fa6b14954>\",\"WARC-Concurrent-To\":\"<urn:uuid:a9faa086-b23e-4fe7-9dee-da2353f3cffd>\",\"WARC-IP-Address\":\"34.194.149.67\",\"WARC-Target-URI\":\"https://www.30secondsofcode.org/articles/s/javascript-memoization\",\"WARC-Payload-Digest\":\"sha1:CBK5QVERUZVTL4PRTEJ3U63NIEOAGL7E\",\"WARC-Block-Digest\":\"sha1:YOUN35732WTUKBZIIWZNBYUON5CZYMFP\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-40/CC-MAIN-2022-40_segments_1664030337803.86_warc_CC-MAIN-20221006092601-20221006122601-00574.warc.gz\"}"}