Proxy in JavaScript

As we can already guess from the name, a Proxy object works as a “proxy” to another object and allows us to customize the behavior of the said object in certain ways. Let’s say you have an obj named awesomeAPI which has some properties and methods. You want to “trap” any calls to the object. May be you want to debug something and log every time a property is read/set on the object? Or when a method is called? Since the object has “API” in it’s name, let’s assume it makes a HTTP call to an external API We want to cache the response instead of hitting the resource every time a method is called – we can use a proxy to do that. In fact there can be so many useful use cases for Proxy in JavaScript as we will see.

A Basic Proxy

To create a new proxy, we need two things – one target object and a handler. The target object is the object we want to proxy. The handler is an object which will define certain methods to control what happens when an operation is requested on the target object through the proxy. The proxy object traps the requests, instead of performing the requested operations directly on target object, the proxy would first see if there’s a handler method defined for that operation in our handler object. If a method is available, it’s called. Otherwise the operation is forwarded to the target object directly.

The description alone might not be clear enough. Let’s go ahead and see a basic example.

const obj = {
  hello() {
    console.log("Hello");
  }
}

const handler = {
  get(target, propKey, receiever) {
    console.log("Trapping GET for " + propKey);
    return target[propKey]
  }
}

const proxiedObject = new Proxy(obj, handler);
proxiedObject.hello();

If you run the code example, you will notice a message on your console – “Trapping GET for hello” followed by the actual “Hello” printed by the target object. What’s happening here? We are creating a new Proxy object for the obj object. We have a handler which sets a trap for get. Now any time we access a property on proxiedObject, the get method on the handler is called with the target object, name of the property and the receiver. We will focus on the property name and the target arguments for now. In our handler code, we have just logged the name of the property on the console and then returned the actual value from the target object. We could of course return any value we wish – may be a transformed value? a cached value? Well, anything we wanted.

You may be wondering – we made a function call, hello() but why would that get trapped by get which is for property access? Methods in JavaScript are actually properties. A method call happens in two stages – get the method (read the property) and then an apply call. So when we called proxiedObject.hello(), it looked up the hello property first. Then called it.

Traps in Our Proxies

The methods we define on the handler objects correspond to certain operations. For example, get is called during property lookup, has is called when the in operator is used, set is for setting property values.  These methods are the “traps” for the corresponding operations. Traps are optional, you can just define the ones you need. If any trap is not set for a particular operation, it’s forwarded to the target object directly.

Here’s an example:

const numberStorage  = {
  number: 0
}

const handler = {
  set(target, propKey, value, receiever) {
    target[propKey] = value * value;
    return true;
  }
}

const squaredNumberStorage = new Proxy(numberStorage, handler);

squaredNumberStorage.number = 2;
console.log(squaredNumberStorage.number);

In this example, we have trapped the property set operation and instead of storing the number as it is, we are squaring it and saving the squared value. However, we have defined no traps for the get operation, so when we access the number,  the operation is forwarded to the target object and we get the actual value without any changes.

Now that you know how to trap the operations on an object using a Proxy, you can check out the available traps from the awesome MDN docs here.

Going Ahead

There is an excellent chapter on meta programming with proxies in Exploring ES6 book. The MDN docs on the Proxy object is also pretty nice with adequate examples and complete API references.

 

 




One thought on “Proxy in JavaScript

Leave a Reply

Your email address will not be published. Required fields are marked *