Leveraging the power of Proxy in Javascript

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.

proxy-syntax

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 the in operator.
  • deleteProperty: Intercepts property deletion.
  • apply: Intercepts function calls.
  • construct: Intercepts the new 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 the name 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 the area property is being accessed.
  • If so, it calculates the area based on the width and height properties of the target object.
  • This ensures that area always returns the correct value even if width or height 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:

  1. Intercepting Method Calls:
    • The get trap intercepts property access on the catProxy object.
    • When a property is accessed, the get trap checks if it is a function (method).
  2. 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 is true, it throws an error, preventing the method from executing.
    • If isDead is false, it calls the original method using apply, passing the correct context (this) and arguments.
  3. Avoiding Duplicate Logic:
    • The extra logic (checking the isDead flag) is defined once in the get 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 the cat object.

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

Comments

Let’s make a great impact together

Be a part of BraveBits to unlock your full potential and be proud of the impact you make.