CodeWithBazzyLogo

Mohammad Basit

Proxies in JavaScript - A Powerful Tool for Customization

JavaScript is a versatile and flexible language that offers a wide range of features for developers. One of the more advanced features in JavaScript is the proxy object, which allows developers to intercept and customize fundamental language operations. With proxies, you can implement advanced features such as memoization, lazy-loading, data validation, and more.

What are proxies?

A proxy is an object that acts as an intermediary between the client and the target object. When you create a proxy object, you can intercept and customize certain operations that are performed on the target object. You can think of a proxy as a wrapper object that allows you to modify the behaviour of the target object.

Example

const target = {
name: "Basit",
age: 26,
};
const handler = {
get: function (target, property, receiver) {
console.log(`Getting ${property}`);
return target[property];
},
set: function (target, property, value, receiver) {
console.log(`Setting ${property} to ${value}`);
target[property] = value;
},
};
const proxy = new Proxy(target, handler);

In this example, we created a target object with two properties, name and age. We also created a handler object that has two methods, get and set. The get method intercepts property accesses on the target object, while the set method intercepts property assignments on the target object.

Finally, we created a proxy object using the target object and the handler object. Now, when we access properties on the proxy object, the get method in the handler object will be called.

Let’s see how this works:

console.log(proxy.name); // Getting name
// Output: Basit
proxy.age = 40; // Setting age to 40
console.log(proxy.age); // Getting age
// Output: 40

Real world examples of proxies:

1. Validation

const user = {
name: "",
phone: "",
};
const validator = {
set: function (target, prop, value) {
if (prop === "phone") {
const phoneRegex = /^\d{10}$/;
if (!phoneRegex.test(value)) {
throw new Error("Invalid phone number");
}
}
target[prop] = value;
return true;
},
};
const userProxy = new Proxy(user, validator);
userProxy.name = "John Doe";
userProxy.phone = "1234567890"; // This will work
userProxy.phone = "1234"; // This will throw an error

In this example, we created a user object with name and phone properties. We also created a validator object with a set method that checks if the phone property is in the correct format before it is assigned to the user object.

2. Memoization

function factorial(n) {
if (n === 0 || n === 1) {
return 1;
}
return n * factorial(n - 1);
}
const cache = {};
const memoizedFactorial = new Proxy(factorial, {
apply: function (target, thisArg, args) {
const n = args[0];
if (n in cache) {
console.log(`Returning cached result for ${n}`);
return cache[n];
}
const result = target.apply(thisArg, args);
cache[n] = result;
console.log(`Caching result for ${n}`);
return result;
},
});
console.log(memoizedFactorial(5)); // Output: Caching result for 5, 120
console.log(memoizedFactorial(5)); // Output: Returning cached result for 5, 120

In this example, we created a factorial function that calculates the factorial of a number. We also created a cache object to store the results of previous computations. Finally, we created a memoizedFactorial object using a proxy that intercepts calls to the factorial function and caches the results.

Conclusion

Proxies are a powerful feature in JavaScript that allows you to intercept and customize fundamental language operations. With proxies, you can implement advanced features such as memoization, lazy-loading, data validation, and more. By using proxies, you can write more efficient and flexible code that meets the specific needs of your application.