Proxy in JavaScript

Photo by Jordan Harrison / Unsplash

Imagine you have a library/SDK that you expose to others to use on their websites. And you want to know what all functions are called by your library users, and how many times. Maybe you want to deprecate the unused ones or may be you want to log the unavailable function calls made on your library. Or say you want to create an internal debugger sort of thing that logs something whenever any function is called in a particular object.

All these scenarios boil down to keeping track of the function calls made on the object. And the most trivial way we can solve this is by patching each function with a little code, like so:

const obj = {
	methodOne() {
		// logs about `methodOne` being called
		// method code here
	}
	methodTwo() {
		// logs about `methodOne` being called
		// method code here
	}
}

This works but it could be a lot of work when you have a lot of such objects and a lot of methods inside. Patching each function with this extra code can also make the function body less readable and of course, it might bloat the file size a bit.

We have a much better way of dealing with this in JavaScript - Proxy

How Proxies work

As the name suggests, by using a Proxy you can create an intermediate entity that internally calls our object's properties and methods. Not just that, but you can define at a central place what should happen when these properties/functions get read or written!

Let's see a simple example to understand this:

const target = {
  message1: "hello",
  message2: "everyone"
};

const handler = {
  get: function (target, prop, receiver) {
    if (prop === "message2") {
      return "world";
    }
    return Reflect.get(...arguments);
  },
};

const proxy = new Proxy(target, handler);

console.log(proxy.message1); // hello
console.log(proxy.message2); // world

This is the simplest example to understand the power of Proxy. Here we are trying to proxy the target object. We want to return world when target.message2 is accessed. For other properties, they should simply work as defined in target object. This is as simple as defining a handler object with a getter function and telling the proxy to use it against any target object.

Getting Proxy to work for us

Extending from the above example, let's see how we can carry out some use cases:

Logging just method calls

const target = {
  message1: "hello",
  start: () => { return 'world'; }
};

const handler2 = {
  get: function (target, prop, receiver) {
    if (typeof target[prop] === "function") {
      logFunctionCall(prop);
    }
    return Reflect.get(...arguments);
  },
};

const proxy2 = new Proxy(target, handler2);

console.log(proxy2.message1); // won't log anything
console.log(proxy2.start()); // will log the function call

Logging unavailable method calls and show a message

How nice would it be if you could know what unavailable properties your users access on your library? And when they do so you could show them a message in the developer console about it!

Here is how you can do it easily:

const target = {
  message1: "hello",
  start: () => { return 'world'; }
};

const handler3 = {
  get: function (target, prop, receiver) {
    if (typeof target[prop] === "undefined") {
			logUnavailablePropertyAccessToServer(prop);
      console.log(`property ${prop} is not available in the library. Needs this? Log an issue on github.com/user/yourLib/issues`);
			return;
    }
    return Reflect.get(...arguments);
  },
};

const proxy3 = new Proxy(target, handler3);

console.log(proxy3.stop()); // will log function call as unavailable

Note: the above examples just work by defining the get accessor in the handler. You can do a lot more crazy stuff with the set accessor! Possibilities of this amazing utility is endless! You can. find more such useful examples on the MDN doc page too - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#examples

Browser Support

The best part is — Proxy is available in all modern browsers!

Are you getting some crazy ideas of using Proxy in your app? Let us know in the comments!

Until next time!

Kushagra Gour

Kushagra Gour

A creative human!