Proxy
Introduction
A Proxy wraps a target object and intercepts fundamental operations through traps such as get, set, has, deleteProperty, and ownKeys. It lets you customize object behavior without changing every call site.
Proxy is powerful interview material because it combines object semantics, invariants, validation, logging, and the Reflect API used for safe default forwarding.
Why This Matters
Proxies power observable state, validation layers, API clients, access control, deprecation warnings, virtual properties, and testing utilities. They force you to think about what operations JavaScript performs under property syntax and the in operator.
Theory
Target, handler, traps
new Proxy(target, handler) returns a proxy object. The target stores the real data. The handler defines traps for operations. If a trap is missing, the operation forwards to the target normally.
Common traps
get(target, property, receiver) intercepts reads. set(target, property, value, receiver) intercepts writes and should return a boolean. has(target, property) intercepts the in operator. Other traps cover deletion, keys, construction, and descriptors.
Use Reflect for default behavior
Inside traps, Reflect.get, Reflect.set, and friends perform the default operation with normal JavaScript semantics. This avoids subtle bugs with accessors, prototypes, and receivers.
Invariants and cost
Proxy traps cannot lie about certain non-configurable or non-writable properties. Violating invariants throws. Proxy is flexible but can be slower and harder to trace than direct objects.
Visual Diagrams
caller reads proxy.name | Proxy get trap | validate, log, or virtualize v Reflect.get(target, name, receiver) | actual value
A trap can add behavior and then forward the default operation.
Code Examples
get, set, and has traps
Use Reflect inside traps to preserve default semantics while adding behavior.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1var target = { count: 1 };2var proxy = new Proxy(target, {3 get: function (obj, prop, receiver) {4 console.log('get ' + String(prop));5 return Reflect.get(obj, prop, receiver);6 },7 set: function (obj, prop, value, receiver) {8 console.log('set ' + String(prop) + '=' + value);9 return Reflect.set(obj, prop, value, receiver);10 },11 has: function (obj, prop) {12 console.log('has ' + String(prop));13 return Reflect.has(obj, prop);14 }15});16 17proxy.count = 2;18console.log(proxy.count);19console.log('count' in proxy);Coding Exercises
Create a schema-validated object proxy
HardImplement createValidatedObject(target, schema) where schema values are validator functions. The proxy should validate known properties on assignment, reject unknown properties, and forward reads with Reflect.get.
Interview Questions
1What are Proxy traps, and why should `set` return a boolean?
Traps are handler methods that intercept object operations. The set trap represents assignment and must return a boolean indicating success. Returning false can cause assignment to fail, and in strict mode it throws a TypeError.
Follow-ups
- What is the receiver parameter?
- Why use `Reflect.get` inside a get trap?
2Name a pitfall of using Proxy in production code.
Proxy can make behavior harder to trace and may be slower than plain objects on hot paths. Traps must also respect invariants around non-configurable and non-writable properties.
Quiz
1. Which Proxy trap intercepts the `in` operator?
Summary
- Proxy wraps a target and intercepts operations through traps.
- Common traps include `get`, `set`, and `has`.
- Use `Reflect` inside traps for default forwarding semantics.
- Proxy is powerful but should respect invariants and performance costs.
Cheat Sheet
Create: new Proxy(target, handler).
Traps: get, set, has, deleteProperty, ownKeys.
Forward: use Reflect.get/set/has inside traps.
Use cases: validation, logging, virtual properties, access control.
Pitfalls: invariants, strict-mode assignment, performance, debuggability.