ES6+ Modern JavaScript
Proxy & Reflect
Master meta-programming in JavaScript. Learn the Proxy and Reflect APIs to intercept object operations, implement validation, and construct reactive objects.
1. Introduction
JavaScript provides meta-programming APIs to customize how operations are executed. The Proxy object wraps a target object, intercepting and customising core operations (like property lookups, assignments, or function calls). The Reflect object provides matching methods to forward these operations to the target object.
2. Why It Matters
Proxies are the foundation of modern reactive frameworks (like Vue 3). They allow you to write validators, log operations automatically, hide private properties, or trigger DOM updates when properties change, without modifying the target object directly.
3. Real-World Analogy
Think of a Real Estate Agent (Proxy):
- Target Object (The Home Owner): The owner of the house. They want to sell their home but don't want to talk to buyers directly.
- Proxy (The Agent): The agent stands in front of the owner. When a buyer submits an offer (property set check) or asks a question (property get lookup), the agent intercepts the request. The agent validates the buyer's credentials first. If everything looks good, they pass the request to the owner (Reflect target forward).
4. The Proxy and Reflect APIs
A Proxy is created using new Proxy(target, handler). The handler object defines traps to intercept operations. Reflect methods are called inside these traps to forward operations to the target object:
5. Proxy Traps
Common Proxy traps include:
• get: Intercepts property lookups (e.g. proxy.name).
• set: Intercepts property assignments (e.g. proxy.name = 'Bob').
• has: Intercepts in operator lookups (e.g. 'age' in proxy).
• deleteProperty: Intercepts property deletion (e.g. delete proxy.age).
• apply: Intercepts function calls (when the target is a function).
6. Practical Example
This script demonstrates using a Proxy to create a reactive object that automatically triggers DOM updates when properties change:
7. Common Mistakes
- Not returning a boolean from the set trap: The
settrap must return a boolean value indicating whether the assignment succeeded. Returningundefined(e.g. forgetting thereturnstatement) throws a TypeError in strict mode.
8. Quick Quiz
Q1: Which API is commonly used inside Proxy traps to forward the intercepted operation to the target object safely?
A) Object.defineProperty
B) Reflect
Answer: B — Reflect methods share the same parameter signatures as Proxy traps, making it easy to forward operations to the target object.
9. Scenario-Based Challenge
The Schema validation boundary:
You want to enforce a schema validation on a config object: { port: 8080 }. If a developer tries to set a property that is not in the schema, or tries to write an invalid data type, throw an error. Write the Proxy validator handler.
10. Debugging Exercise
Explain why this proxy setter crashes with a stack overflow error, and how to fix it:
const user = { name: 'Alice' };
const proxy = new Proxy(user, {
set(target, prop, value) {
console.log(`Setting ${prop}`);
// Bug: accessing the property on the proxy inside the trap triggers the trap recursively!
proxy[prop] = value; // infinite recursion stack overflow!
return true;
}
});
proxy.name = 'Bob';
View Solution
Diagnosis: Calling proxy[prop] = value inside the set trap invokes the set trap again, causing infinite recursion and a stack overflow error.
Fix: Modify the property on the target object directly, or use Reflect.set() to forward the assignment to the target object:
const proxy = new Proxy(user, {
set(target, prop, value, receiver) {
console.log(`Setting ${prop}`);
return Reflect.set(target, prop, value, receiver); // Forward assignment safely
}
});
11. Interview Questions
🟢 Q1: Explain why the Reflect API is used alongside the Proxy API in meta-programming.
Answer: The Reflect API provides static methods that match the signatures of Proxy traps.
• Forwarding Operations: It makes it easy to forward the intercepted operation to the target object: return Reflect.get(target, prop, receiver).
• Handling Receiver Binding: It correctly handles the binding of the this context (via the receiver parameter) when accessing inherited getter properties on the proxy object.
• Return Values: Reflect methods return a boolean indicating whether the operation succeeded, making error handling simpler.
12. Production Considerations
- • Performance Overhead: Proxies introduce a performance overhead because every property access traverses the trap handler logic. Avoid wrapping high-frequency objects (like array elements inside computational render loops) in Proxies.