JavaScript Proxy and Reflect
Learn how Proxy traps and the Reflect API intercept and control object behavior in JavaScript.
TL;DR
- 01Wrap target objects with
Proxywrappers to intercept standard operations. - 02Define handler traps like
getandsetto customize behaviors. - 03Use the
ReflectAPI to forward default actions inside traps.
Tips
- 01Invoke matching
Reflectmethods inside every proxy trap to preserve default language behavior for properties. - 02Create validation layers using a proxy
settrap to reject invalid assignments before updating targets.
Warnings
- 01Always pass the receiver argument to
Reflect.getto keep getters bound to the correct context. - 02Avoid wrapping objects in performance-critical loops because proxy traps introduce function invocation overhead.
Creating a Proxy
Proxy wrapperWraps target objects using the Proxy constructor with custom handlers.
const target = { name: "Ada" };
const proxy = new Proxy(target, {});
console.log(proxy.name); // "Ada"Handler trapsSpecifies trap functions in handlers to intercept object reads.
const handler = {
get(target, prop) {
return target[prop];
}
};
const proxy = new Proxy({ x: 1 }, handler);Function proxyingWraps executable function objects to intercept call parameters.
function greet(name) { return `Hi ${name}`; }
const pr = new Proxy(greet, {
apply(t, thisArg, args) {
return t(...args);
}
});Common Traps
get trapIntercepts property access lookups and method executions.
const p = new Proxy({ a: 1 }, {
get(target, prop) {
return prop in target ? target[prop] : "missing";
}
});set trapIntercepts property assignments and returns confirmation flags.
const p = new Proxy({}, {
set(target, prop, value) {
target[prop] = value;
return true;
}
});has trapIntercepts the boolean property presence verification check.
const p = new Proxy({ secret: 1 }, {
has(target, prop) {
return prop === "secret" ? false : prop in target;
}
});Reflect Default Behavior
Reflect forwardingInvokes default target operations inside custom proxy traps.
const p = new Proxy({ a: 1 }, {
get(target, prop, receiver) {
return Reflect.get(target, prop, receiver);
}
});Context preservationPasses receivers to Reflect to maintain correct property accessor bindings.
const target = {
_v: 10,
get v() { return this._v; }
};Execution return flagsExposes execution success values as standard true or false flags.
const obj = Object.freeze({ a: 1 });
const ok = Reflect.set(obj, "a", 2); // falsePractical Use Cases
Input validationEnforces variable type constraints prior to committing assignments.
const validator = {
set(target, prop, value) {
if (typeof value !== "number") return false;
return Reflect.set(target, prop, value);
}
};Default attributesSupplies default values when missing property keys are queried.
const fallback = {
get(target, prop) {
return prop in target ? target[prop] : 0;
}
};Common Pitfalls
Losing this contextAvoids method execution failure by forwarding matching receivers.
// Always pass 'receiver' to Reflect.get()Identity checksChecks references carefully since proxies do not equal target references.
const target = {};
const proxy = new Proxy(target, {});
console.log(proxy === target); // falseIn Practice
Wraps an object in a validation proxy to enforce strict data types on property assignments.
- 01Define a strict type validation rules checklist schema.
- 02Instantiate a new Proxy with a custom set trap handler.
- 03Intercept property assignment requests at the set boundary.
- 04Verify that incoming values match the validated schema types.
- 05Apply validated assignments using Reflect set calls.
function createValidatedUser() {
const schema = {
age: "number",
name: "string"
};
return new Proxy({}, {
set(target, prop, value) {
if (prop in schema) {
if (typeof value !== schema[prop]) {
throw new TypeError(
prop + " must be a " + schema[prop]
);
}
}
return Reflect.set(target, prop, value);
}
});
}FAQ
A Proxy wraps target objects to intercept core operations like property reads. You specify custom logic via handler functions called traps. This is useful for validation, logging, and reactivity.
A Proxy intercepts actions on objects. The Reflect API provides matching methods to execute standard behaviors. You call Reflect methods inside traps to forward requests.
Using Reflect methods correctly preserves the this binding context for get accessors. It also returns consistent booleans indicating success, avoiding silent failures in non-strict modes.
The get and set traps intercept property accesses. The has trap handles the in operator. The apply trap intercepts function executions when targets are callable.
Yes, because every trapped interaction calls a handler function. This overhead is fine for configuration boundaries or schemas. Avoid using proxies in tight, performance-critical loops.