You will be able to create a JavaScript Proxy that intercepts property access and assignment, and explain when it is better than ordinary getters and setters.
What it is
A Proxy is an object that wraps another object, called the target, and lets you define custom behavior for fundamental operations such as reading properties, writing properties, deleting keys, or enumerating properties. The custom behavior lives in a handler object, whose methods are called traps.
Mental model: the target is the real data; the proxy is a controlled doorway. When code touches the doorway, your trap can inspect the request, transform it, reject it, or forward it to the target.
Related terms: target, handler, trap, invariant, Reflect.
Why it matters
- Validation: reject invalid property names or values before they reach an object.
- Logging and debugging: record every read or write without changing every property manually.
- Lazy loading: compute or fetch a property only when it is first accessed.
- Default values: return a fallback for missing keys instead of undefined.
- API compatibility: make one object behave like another by intercepting operations.
Syntax or steps
- Create a target object.
- Create a handler object with one or more traps, such as
get,set,deleteProperty, orhas. - Call
new Proxy(target, handler). - Use the returned proxy instead of the target when you want interception.
The smallest useful pattern is:
const p = new Proxy(target, {
get(o, k) {
return o[k];
}
});
Here o is the target and k is the property key. The trap returns the value from the target.
Example
const user = {
name: "Ada",
age: 36
};
const handler = {
get(target, prop) {
if (prop === "age") {
return target.age + 1;
}
return Reflect.get(target, prop);
},
set(target, prop, value) {
if (prop === "age" && typeof value !== "number") {
throw new TypeError("age must be a number");
}
return Reflect.set(target, prop, value);
}
};
const proxy = new Proxy(user, handler);
console.log(proxy.name);
console.log(proxy.age);
proxy.age = 37;
console.log(user.age);
Part by part:
useris the target object.handler.getintercepts property reads. It returns a modified age and usesReflect.getfor other properties.handler.setintercepts assignments. It rejects non-number ages and usesReflect.setto perform the normal write.new Proxy(user, handler)creates the proxy.- Reading
proxy.ageruns the get trap; writingproxy.age = 37runs the set trap.
Common mistakes
- Using the proxy only once and then continuing to use the target. The target is not intercepted; always use the proxy object.
- Returning the wrong value from
set. Returntrueor the result ofReflect.setto indicate success; otherwise assignment may fail silently or throw in strict mode. - Forgetting invariants. A proxy cannot make a non-configurable, non-writable target property return a different value than the target.
- Creating infinite recursion by calling the proxy inside its own trap. Call the target or use
Reflectwith the target.
When to use it
Compare Proxy with Object.defineProperty or ordinary getters and setters.
| Approach | Best when | Limitation |
|---|---|---|
Proxy | You need to intercept many or unknown properties, or operations like delete and enumeration. | Can be harder to debug because behavior is centralized and dynamic. |
Object.defineProperty | You need to control one known property on one object. | Does not intercept arbitrary future properties. |
| Class getters and setters | You want explicit, readable behavior for a fixed API. | Only works for properties you define. |
Use Proxy for generic wrappers, validation layers, and reactive systems. Use defineProperty or getters when the property names are known and the behavior is simple.
Practice
Guided exercise: create a proxy that returns "missing" for any property that does not exist on the target.
const data = { id: 1 };
const safe = new Proxy(data, {
get(target, prop) {
return prop in target ? target[prop] : "missing";
}
});
console.log(safe.id);
console.log(safe.title);
Expected output:
1
missing
Challenge: extend the proxy so that setting id to a non-number throws an error. Hint: add a set trap and use typeof value !== "number".
Quick check
Question: If you modify the original target after creating a proxy, will the proxy see the change?
Answer: Yes. The proxy forwards operations to the target, so changes to the target are visible through the proxy unless a trap hides or transforms them.
Summary
A Proxy lets you intercept operations on an object through handler traps such as get and set. It is useful when you need dynamic, property-wide behavior rather than defining each property manually. Use it as a controlled doorway around a target object.