Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

JavaScript Proxy and Reflect Metaprogramming

Understand Proxy traps, Reflect forwarding, prototype and extensibility operations, proxy invariants, revocation, and practical metaprogramming boundaries.

Levels: Intermediate ~32 min read

Intermediate

Proxy and Reflect expose a controlled metaprogramming layer around JavaScript object operations. A Proxy can intercept operations such as property reads, writes, existence checks, own-key enumeration, calls, and construction. Reflect provides functions that perform the corresponding standard operations explicitly, making it useful for forwarding behavior from a trap.

A Proxy wraps a target with a handler

new Proxy(target, handler) creates a Proxy exotic object. The target is the object whose behavior is being wrapped; the handler contains optional trap methods. If a trap is missing, the corresponding operation is forwarded to the target. The Proxy itself is the object your code interacts with.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does a Proxy handler contain?

const result = ;

The get trap intercepts property reads

The get trap corresponds to the target object’s property-get operation. Its usual parameters are the target, the property key, and the receiver. Returning Reflect.get(target, property, receiver) preserves ordinary lookup semantics while still allowing instrumentation or policy around the operation.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which Reflect operation naturally forwards a get trap?

const result = ;

The set trap intercepts property writes

The set trap receives target, property, value, and receiver. A trap should normally return a Boolean-compatible result indicating whether the write succeeded. Reflect.set is useful when the trap wants to add behavior but preserve the normal [[Set]] semantics.

Interactive Runnable example
Edit

Ready to run.

Quick check

What should a set trap normally return?

const result = ;

The has trap controls the in operator

The has trap intercepts property-existence checks such as property in object. It can implement policy or instrumentation, but proxy invariants restrict what it may report for certain non-configurable target properties.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which operator invokes the proxy has trap?

const result = ;

The deleteProperty trap intercepts delete

deleteProperty can observe or control deletion attempts. Reflect.deleteProperty(target, property) is the direct forwarding operation. As with other traps, the target’s descriptor state places limits on what a proxy may claim.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which Reflect method matches deleteProperty?

const result = ;

ownKeys controls own-key enumeration

The ownKeys trap intercepts operations that request an object’s own property keys, such as Reflect.ownKeys(proxy) and operations built on it. The trap must obey ordering and invariant requirements imposed by the Proxy internal method; it cannot simply invent an arbitrary impossible view of a non-extensible target.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which operation directly asks for all own keys including symbols?

const result = ;

defineProperty and getOwnPropertyDescriptor traps affect descriptors

defineProperty intercepts attempts to define or redefine an own property. getOwnPropertyDescriptor intercepts descriptor retrieval. These traps are tied to the same internal operations taught in the property-descriptor lesson, so their results are constrained by target descriptors and proxy invariants.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which Reflect function forwards a property definition?

const result = ;

Reflect is a forwarding vocabulary, not a second object model

Reflect methods expose many internal operations as ordinary functions. They are especially useful in traps because they accept the same target, key, value, receiver, or descriptor information that the corresponding operation needs. Reflect does not remove Proxy invariants; it gives you a precise way to delegate to standard behavior.

Interactive Runnable example
Edit

Ready to run.

Quick check

Why is Reflect.set useful inside a set trap?

const result = ;

Proxy invariants are hard constraints

Proxy traps do not grant unlimited freedom. ECMAScript requires proxy results to remain consistent with essential internal-method invariants. For example, a trap cannot report a different value for a non-writable, non-configurable own data property, and an ownKeys result cannot omit required non-configurable keys. Violating an enforced invariant produces a TypeError.

Interactive Runnable example
Edit

Ready to run.

Quick check

What can happen when a proxy trap violates an enforced invariant?

const result = ;

A missing trap delegates to the target

Handlers are sparse by design. If a handler does not define a trap for an operation, the proxy forwards that operation to the target. This lets a handler intercept only the behavior it needs to observe or change.

Interactive Runnable example
Edit

Ready to run.

Quick check

What happens when the handler has no trap for an operation?

const result = ;

Revocable proxies can be shut down

Proxy.revocable(target, handler) returns an object containing a proxy and a revoke function. Calling revoke invalidates that proxy. Subsequent internal-method operations on the revoked proxy throw TypeError because its target and handler are no longer available for use.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does revoke() do to a revocable proxy?

const result = ;

Function proxies can intercept calls and construction

If the proxy target is callable, the proxy has a call internal method and can use an apply trap. If the target is constructable, the proxy can also use a construct trap. The construct trap must return an object. This connects Proxy to the function-object model from the previous lessons.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which trap intercepts a call to a callable proxy?

const result = ;

The prototype traps intercept prototype operations

A Proxy can intercept prototype reads and writes through getPrototypeOf and setPrototypeOf. Reflect.getPrototypeOf and Reflect.setPrototypeOf perform the corresponding ordinary operations explicitly. These traps are subject to invariants: for example, a non-extensible target cannot report a different prototype.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which trap intercepts Object.getPrototypeOf(proxy)?

const result = ;
Interactive Runnable example
Edit

Ready to run.

Quick check

Which trap intercepts Object.setPrototypeOf(proxy, value)?

const result = ;

Extensibility traps must agree with the target

isExtensible and preventExtensions intercept extensibility checks and attempts to make a target non-extensible. Their trap results are constrained by the target: a proxy cannot simply report an extensibility state that disagrees with its target.

Interactive Runnable example
Edit

Ready to run.

Quick check

Which trap intercepts Object.isExtensible(proxy)?

const result = ;
Interactive Runnable example
Edit

Ready to run.

Quick check

Which trap intercepts Object.preventExtensions(proxy)?

const result = ;

Use Proxy for behavior boundaries, not mystery magic

Proxy is powerful but changes fundamental object operations. Good uses include validation, logging, access policies, virtualization, compatibility layers, and controlled API boundaries. Keep handlers small, document intercepted operations, and use Reflect to preserve ordinary semantics when that is the goal. Avoid proxies when a plain function, class, or explicit wrapper communicates the design more clearly.

Authoring rules

Think in terms of the operation being intercepted: get, set, has, deleteProperty, ownKeys, getOwnPropertyDescriptor, defineProperty, apply, or construct. Start from ordinary target behavior, then add the smallest necessary policy. Prefer Reflect forwarding when you want normal semantics. Treat invariants as requirements, not obstacles to work around. Remember that a proxy does not recursively wrap everything reachable from its target; only operations performed through that proxy are intercepted.

Practice

Build a validation proxy around a configuration object. Reject unknown writes, log reads, and forward accepted operations with Reflect. Then add a get trap that exposes a computed virtual property without adding it to the target. Inspect the target and proxy separately to see the difference between virtual behavior and stored state. Finally create a revocable proxy and demonstrate its lifecycle.

Specification references

The current ECMA-262 specification defines Proxy exotic objects, their [[ProxyHandler]] and [[ProxyTarget]] internal slots, proxy traps corresponding to essential internal methods, proxy invariants, Proxy.revocable(), and the Reflect operations used to invoke object behavior explicitly. urlECMA-262 — current language specificationhttps://tc39.es/ecma262/

Next step

The next JavaScript phase moves into collections and iteration: iterable protocols, iterators, for...of, generator functions, Map, Set, WeakMap, and WeakSet.

Was this page helpful?

Mark this learning resource complete to track your learning progress.