JavaScript Proxy and Reflect
Learn how JavaScript Proxy and Reflect work: intercept operations with traps and use proxies for validation, access control, and logging.
JavaScript proxies let you intercept and redefine the fundamental operations on objects — reading a property, writing one, checking whether a key exists, calling a function, and more. Paired with the Reflect API, which performs those same operations the "default" way, proxies give you a clean, official mechanism for adding behavior to objects without modifying them directly.
This chapter covers what a proxy is, the most common traps (get, set, apply, has, deleteProperty), how Reflect complements proxies, and several real-world patterns such as validation, access control, and logging.
What Is a Proxy
A Proxy wraps a target object and a handler. The handler is a set of functions called traps, each one intercepting a specific operation. When you interact with the proxy, the matching trap runs instead of the default behavior; if no trap is defined for an operation, the proxy forwards it to the target unchanged.
This is useful whenever you want to layer cross-cutting behavior — logging, validation, default values, access rules — onto an object without touching its own code.
Proxy Syntax
const proxy = new Proxy(target, handler);target: The original object whose operations you want to intercept.handler: An object whose methods (traps) define how operations behave.
You then use proxy exactly as you would the original object; the difference is that your traps run in between.
Understanding the get Trap
The get trap intercepts property reads on the target object. It receives the target, the property key, and the receiver (the proxy itself). It's often used for logging access, computing properties on the fly, or returning default values for missing keys.
Example:
This code sets up a proxy to log property accesses on an object.
- Handler: Defines a
gettrap to log the accessed property. - Target Object: Contains
nameandageproperties. - Proxy: Wraps the
targetobject with thehandler.
When proxy.name is accessed, it logs "Getting name" and returns "John". This is useful for monitoring or debugging property accesses.
Manipulating Object Operations with set and apply Traps
The set Trap
The set trap can enforce rules for property assignments, ensuring properties hold specific types or meet certain conditions.
Example:
This code sets up a proxy to validate and log property assignments on an object.
- Handler: Defines a
settrap to check theageproperty for valid values and log attempts to set it. - Proxy: Wraps the
targetobject with thehandler.
When proxy.age is set, it checks if it's a valid age (0-150). If invalid, it logs an error and throws an exception.
The apply Trap
The apply method in a JavaScript Proxy intercepts function calls. It takes three arguments:
- target: The original function being called.
- thisArg: The value of
thisinside the function. - argumentsList: An array of arguments passed to the function.
Example:
This code sets up a proxy to log function calls and their arguments.
- Handler: Defines an
applytrap to log the arguments when the function is called. - Function:
sumadds two numbers. - Proxy: Wraps the
sumfunction with thehandler.
In the provided code, the apply trap logs the arguments and then calls the original function using target.apply(thisArg, argumentsList). This is useful for logging, debugging, or modifying function behavior dynamically.
The has Trap
The has trap intercepts the in operator. A common use is to hide "private" keys (by convention, names starting with _) so they don't appear to exist from the outside.
Example:
Even though _secret still exists on the target, the in operator reports false, so the key is effectively hidden from code that probes the object.
The deleteProperty Trap
The deleteProperty trap intercepts the delete operator, letting you protect certain keys from removal. It must return true when the deletion is allowed, or throw to block it in strict mode.
Example:
JavaScript proxies are powerful, but use them wisely. Overusing proxies can make your code harder to understand and maintain. Note that proxies introduce a slight performance overhead compared to native objects.
Reflect API
Reflect is a built-in object that provides one method for each interceptable operation — the exact same set covered by proxy traps (Reflect.get, Reflect.set, Reflect.has, Reflect.deleteProperty, Reflect.apply, and so on). Each method performs the default version of that operation.
This makes Reflect the natural companion to Proxy: inside a trap you usually want to add some behavior and then let the operation proceed normally. Calling the matching Reflect method does exactly that, and it forwards the receiver correctly (important for getters/setters), which a plain target[property] does not. You will see this pattern used in the practical examples below.
Reflect methods also return values instead of throwing — for example Reflect.set returns a boolean indicating success — which makes operations more predictable than their operator or Object.* equivalents.
Here's a quick tour of the key Reflect methods:
1. Reflect.get()
This method is used to get the value of a property from an object.
Example:
2. Reflect.set()
This method is used to set the value of a property on an object.
Example:
3. Reflect.has()
This method checks if a property exists in an object.
Example:
4. Reflect.deleteProperty()
This method deletes a property from an object.
Example:
5. Reflect.ownKeys()
This method returns all the own property keys of an object.
Example:
6. Reflect.apply()
This method calls a target function with given arguments.
Example:
7. Reflect.construct()
This method is used to create a new instance of an object.
Example:
These examples show how you can use Reflect methods to perform common operations on objects in a cleaner and more consistent way.
Practical Use Cases of JavaScript Proxies
Example 1: Automatic Property Initialization
Description: Use JavaScript proxies to automatically initialize undefined properties in an object. This can be useful in situations where objects are dynamically filled with data over time, such as user settings or configurations that may not be set initially.
This code creates a proxy that checks if a property exists on an object. If it doesn’t, the proxy automatically sets a default value for it. This is helpful in preventing errors from missing properties.
Example 2: Access Control
Description: Proxies can enforce read or write permissions on object properties. This example demonstrates a proxy that prevents certain properties from being read or written based on predefined rules, which is particularly useful for managing access to sensitive data.
This code secures an object by controlling access to its properties. It blocks reading 'sensitiveData' and prevents changing 'readOnly' properties, helping keep data safe.
Example 3: Logging and Debugging
Description: Proxies can be used to log interactions with an object, which helps in debugging and monitoring operations. This example creates a proxy that logs all gets, sets, and method calls performed on an object.
This code tracks every time someone accesses or changes a property on the object, which is great for understanding what your code is doing and when.
Example 4: Data Validation
Description: Use proxies for on-the-fly validation of object properties. This is particularly useful for ensuring data integrity when objects are updated dynamically in an application.
This example demonstrates how to use JavaScript's Proxy to validate and log property changes. The validator object checks if the age property is a valid number between 0 and 150. If not, it logs an error and throws an exception. Otherwise, it logs the new value and updates the property. The person object uses this validator to manage its age property, ensuring invalid ages are caught and logged.
Conclusion
Mastering JavaScript proxies lets you control and extend how objects behave without modifying them directly. Proxies can enforce validation and access rules, supply default values, and power logging or debugging tools, while Reflect keeps the underlying operations clean and predictable. Used sparingly, they help you build more dynamic and secure applications.
To go deeper into the operations proxies intercept, see property getters and setters and property flags and descriptors. For the validation pattern shown above, error handling with try...catch and classes are useful companions.