JS is not truly an Object Oriented Programming language. Therefore fulfilling requirements such as Enforcing object property value validation during read and write and take action, defining a property as private, and detecting changes in values can be challenging. There are ways of solving the above-stated problems, such as by using a setter or getter to set default value or throw an error on validation checks. However, the more convenient way to handle these problems is by using the Proxy object.
Proxies are one of the hidden gems in Javascript that many developers do not know of. The Proxy object is a virtualising interface that allows us to control the behaviour of the object. It allows us to define custom behaviour for the basic operations of an object. Let's take an example to understand proxy in a better way.
Let us consider an item as shown below.
let item = {
id: 1231,
name: 'Stock',
price: 136
}
We want to sell this item but the condition is that the selling price should not be less than 100. At the same time, we want to put a check in place that throws the error if we try to read the value of a property that does not exist. Also, we want to define id
as private property.
We can easily solve this problem by writing custom logic while performing get, set ,or property lookup. JS Proxy object exactly helps here. It allows us to add custom behaviour to the fundamental operations on a JS object.
To create a proxy object, we use the Proxy constructor and pass two parameters(target and handler) in it. Defining a Proxy object:
let proxy = new Proxy(target, handler);
Target is the object which is virtualised using Proxy and adds custom behaviour to it. Here, item
object is the target.
Handler is the object in which we define the custom behaviour. The handler object container the trap.
Traps are the methods that gives access to the target object’s property to the handler object. Traps are optional. If trap is not provided, target object’s default methods are used. There are different types of traps such as get, set, has, isExtensible, defineProperty, etc. You can use all of these traps in the handler to define the custom behaviour for target object.
let item = {
id: 1231,
name: 'Stock',
price: 136
}
let handler = {
// check while setting the value
set: function(obj, prop, value) {
if(prop === 'price') {
if( !Number.isInteger(value)){
throw new TypeError('Value passed is not a number');
}
if(value < 100){
obj[prop]= 100;
return true;
}
}
obj[prop]= value;
return true;
},
// check for no access to `id`
// check for property which does not exist
get: function(obj, prop) {
if(prop == 'id'){
throw new Error('Cannot access private property : id');
}
else {
return prop in obj ?
obj[prop] : new TypeError (prop + ' : property does not exist');
}
}
}
var itemProxy = new Proxy(item, handler);
Let's understand the code. We created a proxy called itemProxy
using the Proxy constructor and passed the item
and handler
to it.
Using the get
trap in the handler, we are checking if the property exists in the object or not. Also, we have enforced id as private property and made it inaccessible.
Using the set
trap in the handler, we are checking if the property passed is price, if the value being passed to assign is an integer and also, we are putting a modifier to assign the value 100 by default if the price is less than 100.
console.log(itemProxy.price); // 136
itemProxy.price = 45;
console.log(itemProxy.price); // 100
In a similar manner, we can define handlers to detect changes to the value of object properties which we will discuss some other time.
I hope this article helped all of us understand Proxies. To learn more, visit the MDN docs.
Love reading about Javascript, Web optimisations, Vue.js, React, and Frontend in general? Stay tuned for more.
Wanna connect? You can find me on LinkedIn, Twitter, GitHub.
Top comments (3)
Thanks for adding it mate!
Do checkout my other write-up as well
Tree shaking in Javascript
Add to the discussion