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: Basitproxy.age = 40; // Setting age to 40console.log(proxy.age); // Getting age// Output: 40Real 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 workuserProxy.phone = "1234"; // This will throw an errorIn 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, 120console.log(memoizedFactorial(5)); // Output: Returning cached result for 5, 120In 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.