How to Master the Proxy API in JavaScript

Looking at practical use-cases of metaprogramming

Ferenc Almasi
May 17 · 6 min read
Tutorial about the Proxy API in JavaScript
Tutorial about the Proxy API in JavaScript
Photo by Ferenc Almasi on Unsplash

JavaScript is a pretty flexible language. It is loosely typed and dynamic in nature. You’ve probably already know that its first version — back then known as Mocha — was created in only 10 days. Being this flexible meant that developers could easily extend it to cater for their custom use-cases.

With the Proxy API, this flexibility is taken to a new level. You can hook into the meta-level to change the behavior of JavaScript itself.


What is Metaprogramming?

Metaprogramming can mean several things. But in the context of the Proxy API, it means that the program can modify itself during execution.

With the help of the Proxy API, you have the ability to redefine the semantics and behavior of fundamental operations like property lookup or assignments. That is all that the Proxy API is. So how does it work?


It’s a Trap

Proxies are using so-called “traps” to give custom behavior to operations. They are methods that intercepts the operation, just like a proxy server would intercept a network request. Let’s take a look at a couple of examples to see how they work.

Analogy of the Proxy API that sits in between a property lookup
Analogy of the Proxy API that sits in between a property lookup
The Proxy API sits between a property lookup and produces an error if a property is not defined

Getting Values

First, let’s take a look at how we can intercept property lookup and provide custom behavior when we try to read a property.

Defaulting to custom values

Imagine that you want to build your logic around returning an empty object, whenever one of your properties is not defined. You don’t want to use undefined, you want to have a fallback value. Which in this case is an empty {}. We can do this in the following way:

We assign man to a new Proxy. The proxy accepts two arguments:

  • Target: The first argument is the target object that we want to wrap into a Proxy. It can be even an array, a function, or another Proxy. Here we use an empty object.
  • Handler: The second argument is an object that has predefined methods. We can use these methods to define custom behavior for the operations. They are called traps. The get trap is used for getting property values.

In this example, we simply check if the property exists on the object. If it’s not, we return with an empty object.

proxy property lookup
proxy property lookup

If you request this in the console, you can see that man is a Proxy. Whenever I try to access a non-existent property, it will return an empty object.

To make things more readable, we can outsource this call into a function. This way, we can reuse it later whenever we need it.

If we wrap an object into this function, it will return a Proxy with the new functionality. This also hides the underlying logic and makes things more readable. The intention is clearly conveyed.

outsourcing the Proxy into a function
outsourcing the Proxy into a function

Alerting

Let’s see a more practical example. Now you want to know whenever your properties are not defined. You can put some alerting in place with it.

Calling this with the same object as before, you will get an error logged out to the console whenever a property is referenced that is not defined. This makes it easier to spot potential issues in your application.

If we don’t have a property, the proxy will print out an error
If we don’t have a property, the proxy will print out an error

Smart arrays

We can also improve array lookups by implementing a custom logic for the get trap.

This trap will get the original value — using the Reflect API — if the index is a positive number. If we pass in a negative number, however, we can retrieve values from the end of the array.

Improving array usability with the get trap, using the Proxy API
Improving array usability with the get trap, using the Proxy API

We can further enhance this to also support intervals.

Smart objects

The same can we done with objects. Say you want to reach a deeply nested property, without having to write out the full path. You only know the name of the object, and the property you are looking for. We can do this with the help of a recursive function.

Now you can reach properties, just like they would exist on the top level. The question is, should you?


Setting Values

Like the get trap can be used to intercepting property lookup, the set trap can be used for assignments. Everything remains the same, except we need to use set instead of get. Let’s have a look.

Validating properties

The most common case is to validate properties. Let’s create a validator that validates a user object.

Unlike the get trap, set has three parameters. One for the object, one for the property and one for its value. As you can see, we always have to return something.

If some of the validation fails, we return false. This will prevent the property to be set. At the end we can use the Reflect API, to set the value if the validation was successful.

Validating an object with the set trap
Validating an object with the set trap

As you can see, the value won’t be set if the email is invalid. The same is true for age.

Making properties read-only

We can also use the trap to create read-only properties. This way, you can ensure that no one can change them.

Here we used a function that’s only purpose is to write an error to the console. The proxy not only prevents assignments, but delete or any kind of extension.

The proxy makes the object read-only
The proxy makes the object read-only

You can also put some custom logic in place to make only a selected number of properties read-only.

Converting strings to numbers

Another use-case would be to automatically convert strings to numbers. This can be done with some regex magic.

All we need is an if statement to reassign the value if it only contains numbers. Now whenever you assign a value that is a string, but only contains numbers, the proxy will convert it for us.

Parsing strings to numbers with Proxy
Parsing strings to numbers with Proxy
If the string only contains numbers, it will be converted to an integer

Conclusion

Now you should have a pretty strong foundation about the Proxy API in JavaScript. Once you get the hang of it, this can be a pretty powerful tool to enhance your everyday operations.

Do you know other use-cases that the Proxy API can be used for and is not mentioned in this tutorial? Let us know in the comments! Thank you for taking the time to read this article, happy coding!

A note from Plain English

Did you know that we have launched a YouTube channel? Every video we make will aim to teach you something new. Check us out by clicking here, and be sure to subscribe to the channel 😎

JavaScript In Plain English

New articles every day.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store