Proxy Method: JavaScript Design Pattern

Ayesha SiddiquaAyesha Siddiqua
7 min read

In this article, we will see what are Proxy Patterns using JavaScript, which is one of the Design Pattern.

Prerequisites: Javascript

But before moving ahead with Proxy Patterns, what are Design Patterns?

→ Design patterns are elegant solutions to solve software problems. They are mostly associated with object-oriented programming. The design patterns will provide us with a format or rules on how to relate the created classes and how should they communicate with each other. So, if you're a person who is familiar with OOP in any language, then it is high time to get to know about design patterns!!

What is a Proxy Pattern? Why is it necessary?

→ Proxy Pattern is an object that is a placeholder for the target object, with which we get more control over the interactions with the target object. If an object has a proxy, then the user will not directly interact with this object because the proxy acts as a middleman. So, any request that is sent by the user will be passed to the proxy object and then forwarded to the target object if necessary.

→ As said earlier, Proxies help us add more functionalities when interacting with the target object, such as logging, validation, formatting, debugging.

Javascript provides us with a built-in Proxy object to create a new Proxy. The Proxy takes two arguments: the target object and the handler object. The handler object is an object that we create to add functionalities to the target object.

Proxy Syntax

Implementation

We can perform different methods with Proxy handler. But the most common methods are the get and set method.

  • get method → used to retrieve a property from the target.

  • set method → used to set a property in the target object.

The get and set method are written in the format given below

get and set method syntax

Since we are now familiar with the syntax and methods, let's move ahead and write some code to understand it more practically.

Example-1

– Let's create an object named review with keys country and rating.

const review={ country: 'India', rating: 89 , };

– Creating a Proxy with a variable name reviewProxy.

const reviewProxy= new Proxy(review, {});

The first argument is the target object and {} represents a handler object. Refer the syntax mentioned earlier for creating a Proxy if you are stuck.

– Let's add a simple get method to access the property country from the object.

const review={
    country: 'India',
    rating: 89 ,
};

const reviewProxy=new Proxy(review, {

    get:function(obj, prop){
        console.log(`The name of the ${prop} is ${obj[prop]}`)
    },
});

– Now adding set method to modify the review object.

const review={
    country: 'India',
    rating: 89 ,
};

const reviewProxy=new Proxy(review, {

    get:function(obj, prop){
        console.log(`The name of the ${prop} is ${obj[prop]}`)
    },

    set:(obj, prop, value)=>{
        console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);     
     }

});

The third argument of the set method stores the new value.

– Done! Let's try to see what happens when we try to retrieve or modify the target object.

reviewProxy.country;
reviewProxy.rating= 85;

Output for example-1 code

– When we accessed the country property with the get method, we got the output as The name of the country is India. While **when we tried to modify the object with the set method, we got the output as Changed rating from 89 to 85. In the above example, we see how Proxy acts like a helpful middleman. The user is not interacting directly with the target object but is unaware of it. Therefore, the Proxy ensures the smooth running behind the scenes while the user enjoys the UI without any visible change.

Example-2 : Validation

Proxy is also useful for validation. Validation in the sense that you do not want the user assigning a numerical value to the country or a string value to the rating. This can also be called constraints of the object keys.

– Let us first create a new object named student along with its proxy object studentProxy.

const student={
    name: 'Sara',
    age: 20,
    marks:80
};

const studentProxy=new Proxy(student, {});

– Add a set method. As the name shouldn't have numbers, we will give a condition to the name property to inform the user to enter a valid name.

const student={ name: 'Sara', age: 20, marks:80 };
const studentProxy= new Proxy(student, {

    set:(obj, prop, value)=>{
        if(prop ==='name'){
            if (typeof value !== 'string'){
                console.log('Name must be a string.')
            }} 
 }});

– Let's also add two conditions to the marks property.

First, the value should be a number.

Second, the value should only be in the range 0 to 100.

const student={
    name: 'Sara',
    age: 20,
    marks:80
};

const studentProxy=new Proxy(student, {

    set:(obj, prop, value)=>{
        if(prop === 'name'){
            if (typeof value !== 'string'){
                console.log('Country must be a string.')
            }}

        if(prop === 'marks'){
            if(typeof value!=='number'){
                console.log('Rating should be in numbers.')
            }
            if(value<0){
                console.log('Rating should be positive number.')
            }
            if(value>100){
                console.log('Rating should be in the range 100.');
            }}

        obj[prop]= value;
        return true;        
}});

– We are done!! Let's try to see what happens when we try to modify name and marks in the target object.

studentProxy.name= 34
studentProxy.marks= -10

Output for example-2 code

Example-3: Deprecation of values in object

– With the two examples above, we are now familiar with how proxy works. Now let us see a practical problem where proxy can be used.

Let's consider an object named clotheSize.

const clotheSize ={
    large: 'large',
    small: 'small',
    XL: 'XL',
    XS: 'XS',
    XXL:'larger',
    XXS:'smaller'
}

Let us imagine a scenario where the clothes for the sizing XXL and XXS are no longer available, so we can say that these properties and their corresponding values are deprecated. But the problem is that the user will not know about this situation and will try to access the value 'larger' or 'smaller' from the object.

Since those two properties and values are deprecated, we need to have a replacement for both the property and value whenever the user tries to fetch it. So the solution is to create another object for the XXL and XXS and change these property names from 'XXL' and 'XXS' to 'large' and 'small' respectively and also their corresponding values from 'larger' and 'smaller' to 'large' and 'small'.

On creating another object named deprecatedSize, the code will be

const clotheSize={
    large: 'large',
    small: 'small',
    XL: 'XL',
    XS: 'XS'
}

const deprecatedSize={
    XXL:{
        replacementName: 'large',
        replacementValue: 'large'
    },
    XXS:{
        replacementName: 'small',
        replacementValue: 'small'
    }
}

– Let's now create a proxy object and perform a get method using reflect.

const clotheSizeProxy= new Proxy(clotheSize, {
    get: (target, prop)=>{
        if(prop in deprecatedSize){

            console.warn(
                `${prop} is deprecated`,
                `Use ${deprecatedSize[prop].replacementName} instead`,
            )

            console.log( deprecatedSize[prop].replacementValue);
        }
        if(prop in clotheSize){
            console.log(clotheSize[prop]);
        }
    }
})

In the above code, we are first checking if the prop that is being fetched is present in the 'deprecatedSize' object. If yes then we are returning the 'replacementValue' and also warning the user about the deprecation and to use the 'replacementName' instead from next time.

– Now let's see what happens when we try to access the deprecated value and the value that is still present in the target object (clotheSize).

clotheSizeProxy.XXL; 
clotheSizeProxy.XS;

Output for example-3 code

When we tried to access the deprecated value, it gave us a warning but still gave the output as the new translated version value. While for the property that is still present in the target object, we got the output as 'XS'.

Advantages of Proxy

  1. proxies can improve performance by caching frequently accessed objects.

  2. It provides you with enhanced security.

  3. It grants the control and diversion of requests and the ease to implement.

Disadvantages of Proxy

  1. Use of proxies can lead to more complexity.

  2. The debugging of the code can become challenging.

There are many other design patterns that you can look into after Proxy design. In particular, the design pattern that you might find interesting is the Adapter pattern which will teach you how to make different interfaces work together. Then you can look into Decorator pattern, Factory pattern, and many more where each of them will give you a unique insight.

5
Subscribe to my newsletter

Read articles from Ayesha Siddiqua directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayesha Siddiqua
Ayesha Siddiqua

I write on the technologies that I find interesting while learning🛠️. I share my insights, experience, and opinions on the topics that I come across🙂.