Abhijit Hota
Method Middlewares with JavaScript Proxies
You have an object that is a collection of methods:
const myFunctions = {
constant: (x) => 1,
linear: (x) => x,
sine: (x) => Math.sin(Math.PI * x),
cos: (x) => Math.cos(Math.PI * x),
};
And you want to do the same operation based on the result of the methods:
const scaleToRange = (y, [yi, yf]) => y * (yf  yi) + yi;
const y = myFunctions.sine(x);
const yScaled = scaleToRange(y, [Y_MIN, Y_MAX]);
No problem at all. 100/100 code. No notes. Commit. Push. Rejoice your life.
But you slowly realize that you don’t want to see the unnecessary yScaled
declaration because it is not relevant to your function flow^{1}. For whatever elitist reason that will make you feel like a better developer, you think that it’d better if you could just abstract this scaleToRange
function into the object itself.
// Your dream code which is objectively worse
const y = myFunctions.sine(x, [Y_MIN, Y_MAX]);
You realize what you want is a middleware to your method calls. So you resort to the obvious JavaScript abuse that you love doing so much:
const myFunctions = Object.fromEntries(
Object.entries({
constant: (x) => 1,
linear: (x) => x,
sine: (x) => Math.sin(Math.PI * x),
cos: (x) => Math.cos(Math.PI * x),
}).map(([key, fn]) => [key, (x, [yi, yf]) => (yf  yi) * fn(x) + yi])
);
Now there’s another problem. “3 iterations to declare the object?”, you scoff. Being a JavaScript developer, performance is of utmost priority to you. A dormant section in your brain lights up immediately. “Proxies!”, you exclaim, “aren’t they supposed to do something like this?”. A proxy technically is a middleware after all.
You instinctively open your Bible and lookup for the documentation on JavaScript proxies, simultaneously fighting your sane subconscious thoughts, that are fragments of an article long forgotten about how you probably don’t need proxies.
After a few minutes, you come up with this:
const myFunctions = new Proxy(
{
constant: () => 1,
linear: (x) => x,
sine: (x) => Math.sin(Math.PI * x),
cos: (x) => Math.cos(Math.PI * x),
},
{
get: (target, key) => {
const fn = target[key];
return (x, [yi, yf]) => {
const y = fn(x);
return (yf  yi) * y + yi;
};
},
},
);
Explanation
A
Proxy
in JavaScript is used to intercept and redefine fundamental operations of an object that it wraps. It has two parameters. Atarget
 which is your original object you want to proxy stuff to and from. And ahandler
 which is an object that contains how you proxy the target object. It returns the modified object.In the above code, we are creating a
Proxy
object for themyFunctions
object. Thehandler
object has aget
method which is called whenever a property is accessed on themyFunctions
object. Theget
method receives thetarget
object and thekey
of the property that is being accessed. That enables us to intercept the property access and manipulate it before returning it.
You hear Jerusalem bells ringing. The Roman cavalry choirs are singing. A portal opens up next to you. Brendan Eich steps out and hands you a medal. You have done it. You commit your code and go to sleep. This high will help you fight your imposter syndrome for the next 3 days.
This post has become annoyingly selfaware.

I realize that the given example flows pretty nicely. But in my actual usecase it felt out of place. ↩︎