Back to Blog
JavaScript Proxy Pattern: A Practical Guide
The Proxy object in JavaScript enables you to create a wrapper around another object, intercepting and redefining fundamental operations like property lookup, assignment, and enumeration.
Basic Syntax
javascript
const target = {
name: 'John',
age: 30
};
const handler = {
get: function(target, prop) {
return prop in target ? target[prop] : 'Property not found';
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 'John'
console.log(proxy.unknown); // 'Property not found'
Common Use Cases
1. Validation
Ensure properties meet certain criteria before they're set.
javascript
const userValidator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('Age must be an integer');
}
if (value < 0 || value > 120) {
throw new RangeError('Age must be between 0 and 120');
}
}
obj[prop] = value;
return true;
}
};
const user = new Proxy({}, userValidator);
user.age = 30; // Works
user.age = -1; // Throws RangeError
user.age = 'young'; // Throws TypeError
2. Logging
Track access and modifications to objects.
javascript
const loggingHandler = {
get: function(target, prop) {
console.log(`Accessing property: ${prop}`);
return target[prop];
},
set: function(target, prop, value) {
console.log(`Setting property: ${prop} = ${value}`);
target[prop] = value;
return true;
}
};
const logged = new Proxy({}, loggingHandler);
3. Default Values
Provide fallback values for undefined properties.
javascript
const withDefaults = new Proxy({}, {
get: function(target, prop) {
return target[prop] ?? 'default value';
}
});
console.log(withDefaults.nonexistent); // 'default value'
Advanced Example: Private Properties
javascript
const privateProxy = (target) => {
return new Proxy(target, {
get: function(target, prop) {
if (prop.startsWith('_')) {
throw new Error('Access to private property denied');
}
return target[prop];
}
});
};
const obj = privateProxy({ _private: 'secret', public: 'open' });
console.log(obj.public); // 'open'
console.log(obj._private); // Error: Access to private property denied
Best Practices
- Use Proxies for cross-cutting concerns like validation and logging
- Keep handler functions pure and predictable
- Document the behavior of your Proxy handlers
- Consider using Reflect methods in your handlers
- Be mindful of performance in performance-critical code