Table of Contents
Table of Contents
Introduction to Proxy
JavaScript Proxy objects are an advanced technique introduced in ES6 to provide developers with more flexibility to intercept and customize internal operations on ordinary objects. This addition opens up a range of possibilities for developers to add new dynamic behaviors that are useful for logging, validating, formatting, and sanitizing inputs. This blog post will examine the conceptual implementation of Proxy, its syntax, usage, and practical examples.
Proxy allows the creation of a new object based on the original object with extra self-defined properties that developers wish to integrate into the behaviors of the original object. In other words, a Proxy object can be understood as a wrapper around the original object. It functions as a representative object and acts as a bridge between the original object and the outside environment.
Basic syntax
To create a Proxy object that wraps around an original object, we initiate a new Proxy instance via new Proxy()
, which accepts the original object as the first parameter and the handler object as the second parameter.
Target object
The target object is any standard JavaScript object (or array, function, etc.) that you wish to wrap with a Proxy. This object serves as the base that the Proxy will operate on.
Handler object
The handler object is where the magic happens. It contains traps—functions that intercept operations on the target object. Each trap corresponds to a different type of operation. For example:
get
: Intercepts property access.set
: Intercepts property assignment.has
: Intercepts thein
operator.deleteProperty
: Intercepts property deletion.apply
: Intercepts function calls.construct
: Intercepts thenew
operator.
In the example above, the proxy object defines the set() trap that adds the new behaviors to the internal method [[Set]] of the obj. If we try to access prop that is not existent on obj, we throw appropriate error. Otherwise, the modified getter will return the value of the obj property. We can see that, the proxy will create an additional error thrower if we try to access non-existent prop on an object and this throw would not happen otherwise.
Practical usage
Data validation
We can use Proxy to assess the validity of data before creating a new property or updating the value of an existing property for an object. In this example:
- The
set
trap is used to intercept property assignments. - The trap checks if the
age
property is being set to a number and if thename
property is not empty. - If the validation fails, an error is thrown; otherwise, the property is set on the target object.
Intercept logging
Proxy can make logging property accesses become much easier for debugging purposes. For example, whenever we access a property of an object, we can intercept the [[Get]] internal method to add logs to this method.
- The
get
trap logs a message whenever a property is accessed. - The
set
trap logs a message whenever a property is set to a new value. - This can help track how an object is being interacted with during runtime.
Add new property
Proxy objects can be used to create new properties that automatically calculate their values based on other properties. This can be particularly useful for derived values
- The
get
trap checks if thearea
property is being accessed. - If so, it calculates the area based on the
width
andheight
properties of the target object. - This ensures that
area
always returns the correct value even ifwidth
orheight
changes.
Add extra logic layers
Proxy can also add more logic to the object without the need for code duplication. Suppose we have a cat object with three methods in the following example.
At a later point in time, the developer realizes that there arises the need to add conditional check if the cat is alive before she can sing, run, or catchMice. Because of this the developer may be tempted to do something like this, adding the check for each individual methods. However, this solution is repetitive and making the code duplicate. Assume that the cat obj has 300 methods instead of just 3, then the new PR would include 300 lines of change, which is quite unacceptable.
At this point, the developer wishes to somehow be able to wrap logic around the object, write some methods to protect its properties while ensure everything else stays the same. Fortunately, the built-in JS Proxy can come to rescue that poor developer as this is its time to shine.
This cat proxy works in three steps:
- Intercepting Method Calls:
- The
get
trap intercepts property access on thecatProxy
object. - When a property is accessed, the
get
trap checks if it is a function (method).
- The
- Wrapping Methods with Additional Logic:
- If the accessed property is a function, the
get
trap returns a new function. - This new function first checks the
isDead
flag. - If
isDead
istrue
, it throws an error, preventing the method from executing. - If
isDead
isfalse
, it calls the original method usingapply
, passing the correct context (this
) and arguments.
- If the accessed property is a function, the
- Avoiding Duplicate Logic:
- The extra logic (checking the
isDead
flag) is defined once in theget
trap. - This logic is applied to all methods dynamically without modifying each method individually.
- This avoids the need to add the same
if (isDead) { throw new Error(...) }
check in each method of thecat
object.
- The extra logic (checking the
By using a Proxy with a get
trap, you can centralize additional logic (like the isDead
check) in one place, avoiding the need to modify or duplicate this logic across multiple methods. This makes the code more maintainable and easier to extend with additional behavior.
Conclusion
By understanding and leveraging Proxy objects, developers can create more robust and maintainable code. Proxies allow the creation of a new object based on the original object with additional self-defined properties and behaviors, functioning as a wrapper around the original object. This approach helps in centralizing logic, reducing code duplication, and ensuring consistent behavior across an application.
SonVH