If you’re reading this and haven’t heard of JavaScript proxies you’re in luck cuz I’m about to introduce you to a fun new JavaScript feature that has awesome potential!
What is a Proxy?
First thing we need to do is define what exactly is this ‘Proxy’ thing?
Lets take a look what the Oxford dictionary says proxy is (Link).
Definition of proxy in English: The authority to represent someone else.
Basically a stand in for someone/something else.
In this context if you’re talking to someone’s proxy for all intents and purposes you are considered to be officially talking to that someone.
In JavaScript the context is objects as you’ll soon find out.
What is a Proxy in JavaScript?
Lets take a look at MDN’s definition of ‘Proxy’ (Link).
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
Uh-oh. I don’t know about you but that definition up there didn’t help me understand proxies in JavaScript so lets go over an example I like to use when explaining proxies.
Imagine a CEO and his assistant/secretary.
Often an assistant’s job is to help the CEO with his emails. An assistant can go thru an email and fix typos,
include relevant links for something that was mentioned in the email etc. before passing it on to the CEO.
In this case the assistant (Proxy) intercepted data that was being sent to the CEO (target), transformed the data
so that it makes more sense to the CEO (target) and then passed it along to the CEO (target).
Another way an assistant can make a CEO’s life easier is by protecting his time. When someone wants to meet
with the CEO (GET a portion of his time) they first need to contact his assistant and based on certain criteria
the assistant can schedule a meeting or (because the CEO gave the assistant the authority) reject the request for a meeting.
In this case someone is trying to GET something from the CEO (target), the assistant (Proxy) intercepts this
request and based on some criteria like who’s asking or what they’re asking for (or some other conditions) allows
access to the target property or responds on it’s own without ever bothering the CEO (target).
Now that we have the theory part taken care of it’s time to move on to the code. YAY!
JavaScript Proxy Code
Now we’re at the fun part!
This is what a basic JavaScript Proxy setup looks like:
const target = {};
const handler = {};
const proxy = new Proxy(target, handler);
target is the target object for which the proxy will stand in for (CEO from our earlier example)
handler is an object containing proxy options. In other words, when should the proxy stand in for the target
object (this will make more sense soon once we look at a proper Proxy example)
proxy is the actual Proxy object that is initialized using new Proxy(target, handler)
Here the proxy doesn’t do anything since we haven’t defined any options for it so it serves as a pass-through object, you can freely work with the target object through the proxy without it interfering.
Traps
That handler up there contains proxy options and those options are called traps.
When you define a trap you’re telling the proxy when to step in and execute some custom behavior, if a trap
isn’t defined the proxy defaults to forwarding the operation to the target.
The 2 most useful traps and the ones you’ll probably be using the most are get and set traps.
Get trap
The get trap is called when ever you try to access a targets property through the proxy, like so:
const target = {};
const handler = {
get: (target, property) => {
console.log(`Accessing property '${property}'`);
return target[property];
}
};
const proxy = new Proxy(target, handler);
proxy.a;
// logs "Accessing property 'a'" to the console
Get is a method that accepts target (the target object) and property (the property we’re trying to get).
Here when you try getting property ‘a’ through the proxy it first logs what you’re doing to the console then returns the value of that property.
Set trap
The set trap is called when ever you try to assign a new value to a targets property through the proxy
const target = {};
const handler = {
set: (target, property, value) => {
console.log(`Updating property '${property}' with value
'${value}'`);
target[property] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
proxy.a = 'NewValue';
// logs "Updating property 'a' with value 'NewValue'" to the console
Set is a method that accepts target (the target object), property (the property we’re trying to update)
and value (the value we’re assigning to the property).
In this example we’re updating target’s ‘a’ property through the proxy this operation is intercepted by the proxy’s
set trap which logs the property we’re updating and the value.
Note that the set trap returns a boolean value. True if the assignment succeeded or false which throws a TypeError if you’re in strict mode.
Using a Proxy to avoid accessing property of undefined
So far we haven’t used proxies for anything particularly useful, let’s change that.
Lets write some code that will help us avoid accidentally accessing a property of a non-object
const target = {};
const handler = {
get: (target, property) => {
target[property] = (property in target) ? target[property] : {};
if (typeof target[property] === 'object') {
return new Proxy(target[property], handler);
}
return target[property];
}
}
const proxy = new Proxy(target, handler);
proxy.x.y.z;
Here the interesting part is the get trap.
It intercepts the attempt to get a property and checks if the property exists on the target, if it does it sets the
value of the property to itself (does nothing basically) if it doesn’t initialize that property with an empty object.
Next it checks if the property is an object and if it is return a new proxy with the same handler but the target now is the object in target[property] because Proxies don’t propagate down to other objects inside the target object.
The last return is there just to return the target property in case it isn’t an object.
Now when we try to access target x.y.z through the proxy it doesn’t throw Cannot read property ‘y’ of undefined but quietly creates objects.
Watch out! I setup this example real fast so it’s untested. For serious use more effort needs to be invested in to it.
More Examples
You can find more cool Proxy examples over at MDN (Link).
The ones I like is the basic example that returns a default value when the property that’s being accessed isn’t
in the target and the one that modifies the DOM using a proxy set trap. Cool.
Wrap Up
Proxies aren’t all sunshine and rainbows, they’re known for their shitty performance (check out this Link) but even with the performance issues proxies are a cool new JavaScript feature with awesome amounts of potential and how successful proxies are depends on how creative we developers are when we use them.