Objects in JavaScript are useful data types that let us define complex data with simple key-value pairs, like a dictionary. Sometimes, you might want to change how JavaScript objects work by default. This is where Proxy Objects are helpful. In this article, we will discuss what proxy objects are, why they are useful, and how to use them.
What is a Proxy Object?
Before understanding what a Proxy Object is, let's look at the word Proxy
. A proxy means something that acts like the original thing but isn't the original thing. Similarly, a Proxy Object is an object created using the original object that can intercept and change how the original object works.
The Proxy
constructor takes two parameters
target: the object you want to create a proxy for
handler: an object with operations you want to change or redefine
const proxyObject = new Proxy(target, handler)
How Does a Proxy Object Work?
When we create Proxy Objects with a handler that has operations you want to change, it intercepts those operations, catches the call to the target object, and runs the custom logic you defined for those operations.
The operations are called traps, which are basically the internal methods of an object. Some of them are:
get
set
deleteProperty
Here, I have created a simple visual showing how a Proxy Object works. If we try to access or set a value, it intercepts and runs the operations (traps) defined in the handler.
Alright, I hope the what and how of Proxy Objects are clear. Next, we will discuss some use cases to show why Proxy Objects are useful.
Use cases of Proxy Object
Logging
Let's say you want to create a system where every time a property is accessed from the object, it logs the information.
const platform = {
type: "peerlist.io",
handle: "sachin87",
};
const proxyPlatformObj = new Proxy(platform, {
get(target, key) {
console.log(`[Info]: Accessing ${key} at ${Date.now()}`);
return target[key];
},
});
// try to access the property
proxyPlatformObj.type;
// [Info]: Accessing type at 1729661722827
// 'peerlist.io'
This is a very simple use case, but it's useful when logging is needed, and you can expand it to do more advanced things.
We can also let users access properties that aren't directly available. For example, in the case above, we might want the full URL of the platform with the user handle.
const proxyPlatformObj = new Proxy(platform, {
get(target, key) {
console.log(`[Info]: Accessing ${key} at ${Date.now()}`);
if (key === "url") {
return `https://${target.type}/${target.handle}`;
}
return target[key];
},
});
// try to access the url property
proxyPlatformObj.url;
// [Info]: Accessing url at 1729662118855
// 'https://peerlist.io/sachin87'
Validation
Another use case is checking the value before adding it. For instance, let's say we want to check the handle's value before setting it. We will validate two basic conditions:
It should be in lowercase
It can be alphanumeric
const proxyPlatformObj = new Proxy(platform, {
set(target, key, value) {
if (key === "handle" && !(/^[a-z0-9]+$/.test(value))) {
console.error(`[Error]: ${key} should be in small case and can be alphanumerical`);
} else {
return Reflect.set(target, key, value);
}
},
});
proxyPlatformObj.handle="Sachin87"
// [Error]: handle should be in small case and can be alphanumerical
You might be wondering what Reflect.set(target, key, value)
is. It's a namespace object with static methods for calling JavaScript object's internal methods that can be intercepted. If you don't want validation for all properties, you can use the Reflect
object to keep the default behavior.
We talked about two use cases logging and validation, but you can intercept other internal methods based on your needs.
Conclusion
We talked about what a Proxy Object is, how it works, and some of its uses. A Proxy Object is helpful, but we should be aware of its downsides. We should use it only when necessary to avoid adding complexity or bugs by mistake.
That's all for this topic. Thank you for reading! If you found this article helpful, please consider liking, commenting, and sharing it with others.