JavaScript proxies: a simple factory for memoized functions

More about the Proxy class introduced by ES6: providing an apply trap function in the handler passed to Proxy‘s constructor, we can intercept and modify call to the target function we pass to the same constructor.
Exploiting this feature, we can e.g. implement a very simple memoize function, which return a wrapper function that call the original function and caches its return value, avoiding recalculation - this can be useful when such calculation is time- o money-expensive.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function memoize(fn) {
const results = {}
return new Proxy(fn, {
apply: function(target, thisArg, argumentsList) {
const key = argumentsList.join(':')
if(!results.hasOwnProperty(key)) {
const result = target.apply(thisArg, argumentsList)
results[key] = result
}
return results[key]
}
})
}

function sum(a, b) { console.log(`${a} + ${b}`); return a+b ;}

sum(10, 20) // 10 + 20
sum(10, 20) // 10 + 20

let mem = memoize(sum)
mem(10, 20) // 10 + 20
mem(10, 20) // no output
sum(100, 200) // 100 + 200

The same approack works when the function we need do memoize is a member of an object, accessing siebling members of the object itself during the calculation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let container = {
x: 100,
sum: function(a, b) { return a + b + this.x; }
}

console.log(container.sum(11, 19)) // 130

container.x = 200
console.log(container.sum(11, 19)) // 230

let memContainer = {
x: 100,
sum: memoize(container.sum)
}

console.log(memContainer.sum(11, 19)) // 130

memContainer.x = 200
console.log(memContainer.sum(11, 19)) // 130
console.log(memContainer.sum(11, 20)) // 231