JavaScript Proxy: simplify code management and maintenance

  



JavaScript is an extremely powerful and versatile language, but like all programming languages, it can be subject to challenges in terms of maintainability and code readability. One of the most interesting features introduced in the most recent versions of JavaScript is Proxy.

This tool allows you to create "proxy" objects, which act as intermediaries between the operation performed on an object and the object itself. Essentially, a proxy is an object that can "intercept" and customize operations on another object, such as reading, writing, function calls, and more.

In this article, we will explore the main benefits of using Proxy and how it can simplify your code, improving its maintainability. We will also show a concrete example to highlight how Proxy can simplify operations that would otherwise require multiple lines of code.

🔗 Do you like Techelopment? Check out the website for all the details!


What is a Proxy in JavaScript?

A Proxy in JavaScript is an object that allows you to define custom behaviors for basic operations, such as reading and writing properties, calling functions, and handling methods get, set, apply, construct, etc. A proxy is created using the Proxy constructor, which takes two arguments:

  1. target: the object you want to "proxy".

  2. handler: an object that defines the methods to be invoked in response to operations on that target.

Here is the basic syntax to create a proxy:


const handler = {
    get: function(target, prop, receiver) {
        // Logic to intercept access to properties
    },
    set: function(target, prop, value, receiver) {
        // Logic to intercept the assignment of values
    }
};

const proxy = new Proxy(targetObject, handler);


Main Benefits of Using JavaScript Proxy

1. Intercept and customize operations on objects

With a Proxy, you can easily intercept operations on objects, such as reading, writing, and method invocations. This allows you to customize the behavior of your code without directly modifying the target objects.

Example of intercepting a property access:


const user = {
    name: 'John',
    age: 30
};

const handler = {
    get(target, prop) {
        if (prop === 'name') {
        return `Hello, ${target[prop]}!`;
        }
        return prop in target ? target[prop] : 'Property not found';
    }
};

const proxy = new Proxy(user, handler);
console.log(proxy.name); // "Hello, John!"
console.log(proxy.age);  // 30
console.log(proxy.email); // "Property not found"

In this case, we can intercept the reading of the name property and add some custom logic, without modifying the original user object.

2. Centralized data validation

Another significant advantage of using Proxy is that you can implement centralized validation logic when assigning values ​​to object properties. Instead of having to write validation code for each property, you can centralize it in the Proxy handler.

Example of validating properties before assigning a value:


const user = {
    name: '',
    age: 0
};

const handler = {
    set(target, prop, value) {
    if (prop === 'age' && (value < 0 || value > 120)) {
        console.error('Invalid age!');
        return false;
    }
    target[prop] = value;
    return true;
    }
};

const proxy = new Proxy(user, handler);
proxy.age = 25;  // It works
proxy.age = -5;  // Invalid age!

In this example, age validation is handled directly in the Proxy, centralizing the logic and reducing the risk of errors scattered throughout the code.

3. Monitoring and logging of operations

A Proxy can also be used to monitor and log object operations, such as reading and writing. This is useful, for example, in situations where you want to track changes to an object for debugging or auditing purposes.

Example of operation log:


const data = {
    name: 'Alice',
    balance: 1000
};

const handler = {
    get(target, prop) {
        console.log(`Getting ${prop}`);
        return prop in target ? target[prop] : undefined;
    },
    set(target, prop, value) {
        console.log(`Setting ${prop} to ${value}`);
        target[prop] = value;
    }
};

const proxy = new Proxy(data, handler);
console.log(proxy.name);   // Getting name
proxy.balance = 2000;      // Setting balance to 2000


Practical Example: config Object with Default and Validation

Imagine you have a config object that contains the settings for an application. Without Proxy, you would have to manually check if a property exists, assign default values, and validate the data every time you change it.

Let's first see how it would be done without Proxy and then how Proxy simplifies everything.

🚫 Without Proxy: Verbose and repetitive code


const config = {
    theme: "light",
    language: "en",
    fontSize: 14
};

function getConfig(prop) {
    return config[prop] !== undefined ? config[prop] : "⚠ Default value";
}

function setConfig(prop, value) {
    if (prop === "fontSize" && (typeof value !== "number" || value < 10 || value > 30)) {
        console.error("❌ Invalid fontSize! Must be between 10 and 30.");
        return;
    }
    config[prop] = value;
}

// Usage
console.log(getConfig("theme")); // "light"
console.log(getConfig("unknown")); // "⚠ Default value"

setConfig("fontSize", 50); // ❌ Error
setConfig("fontSize", 20); // ✅ It works
console.log(getConfig("fontSize")); // 20

Problems:

  • You should always check if a property exists (getConfig).

  • You need to manually validate the data (setConfig).

  • If you have many properties, the code becomes difficult to maintain.


With Proxy: Simpler and more maintainable


const defaultConfig = {
    theme: "light",
    language: "en",
    fontSize: 14
};

const handler = {
    get(target, prop) {
        return prop in target ? target[prop] : "⚠ Default value";
    },
    set(target, prop, value) {
        if (prop === "fontSize" && (typeof value !== "number" || value < 10 || value > 30)) {
            console.error("❌ Invalid fontSize! Must be between 10 and 30.");
            return false;
        }
        target[prop] = value;
        return true;
    }
};

const config = new Proxy(defaultConfig, handler);

// Usage
console.log(config.theme); // "light"
console.log(config.unknown); // "⚠ Default value"

config.fontSize = 50; // ❌ Error
config.fontSize = 20; // ✅ It works
console.log(config.fontSize); // 20

🎯 Why is Proxy better?

No more manual checks: If a property does not exist, it automatically returns a default value.
Centralized validation: If a value is incorrect, the Proxy intercepts it and prevents the assignment.
Cleaner, more reusable code.


Conclusion

JavaScript Proxy is a powerful tool that can simplify many complex operations and make your code more maintainable and readable. It allows you to intercept operations on objects, centralize logic such as validation, logging, and calculations, greatly improving the maintainability of your code in the long run. With concrete examples such as managing a shopping cart, it is easy to see how Proxy can simplify writing more robust and maintainable code.

Using Proxies strategically can be a key resource for improving code quality in complex projects.

 

Follow me #techelopment

Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment