Proxy and Reflect
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object (like property lookup, assignment, enumeration, function invocation, etc.).
Reflect is a built-in object that provides methods for interceptable JavaScript operations. The methods are the same as those of proxy handlers.
1. The Proxy Object
A Proxy is created with two parameters:
- target: The original object which you want to proxy.
- handler: An object that defines which operations will be intercepted and how to redefine intercepted operations (traps).
Basic Syntax
const target = {
message1: "hello",
message2: "everyone"
};
const handler = {
get(target, prop, receiver) {
if (prop === "message2") {
return "world";
}
return Reflect.get(...arguments);
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.message1); // "hello"
console.log(proxy.message2); // "world"
2. Traps
"Traps" are methods that provide property access. This is analogous to the concept of traps in operating systems.
Common traps include:
get(target, prop, receiver): Intercepts reading properties.set(target, prop, value, receiver): Intercepts writing properties.has(target, prop): Intercepts theinoperator.deleteProperty(target, prop): Intercepts thedeleteoperator.apply(target, thisArg, argumentsList): Intercepts function calls.construct(target, args): Intercepts thenewoperator.
3. The Reflect Object
Reflect is a static object (like Math). It provides methods that correspond to the Proxy traps.
Why use Reflect?
- Forwarding default behavior: Inside a Proxy trap, you often want to perform the original operation after doing some custom logic.
Reflectmakes this easy. - Better return values:
Reflect.definePropertyreturns a boolean (success/failure) instead of throwing an error likeObject.defineProperty.
Example: Validation with Proxy and Reflect
const validator = {
set(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
return Reflect.set(obj, prop, value);
}
};
const person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
// person.age = 'young'; // Throws TypeError
// person.age = 300; // Throws RangeError
4. Use Cases
- Validation: Ensuring data integrity before writing to an object.
- Logging/Debugging: Tracking when properties are accessed or changed.
- Data Binding: Automatically updating the UI when the model changes (Vue 3 uses Proxies for reactivity).
- API Mocking: Intercepting calls to non-existent methods.
programming/javascript/vanilla/javascript programming/javascript/vanilla/es6-features