Fun with JavaSript: Proxy Object

Use a Proxy Object to create a simple Lodash Get/Set clone

Dewaun Ayers
6 min readMay 6, 2023
JavaScript Proxy Diagram

JavaScript is wild and ever-changing. Things we only dreamed about doing last year are a reality today. It’s super exciting!

Today I want to talk to you all about JavaScript Proxy Objects. I’ll go into a little bit of the definition of a Proxy Object, some simple use cases, and finally an example of cloning functionality from the awesome Lodash library using JavaScript Proxy Objects.

Some Helpful Links:

What is a Proxy Object?

A Proxy Object is a device that enables you to create a proxy from another object. You can then use this Proxy to redefine operations on the object such as get, set, and delete. When you create a Proxy you can pass two arguments — the target which is just a plain ole JavaScript object, and a handler which is used to define the methods you want to intercept on the object.

Check out this very simple implementation of a JavaScript Proxy:

Adding Custom Handlers

The main benefit of using a Proxy Object is the ability to redefine object operations using custom handler functions. The example below shows a custom get handler function that captures prop2 on the object and returns a different value.

Abstracting Handlers to their own Functions

Abstraction is key to a clean code base (IMO and if done right). With , we can abstract Proxy Object Handlers to their own functions, but be warned that arrow functions () => {}

In the above example we have moved our proxy get and set handlers into proxyGetFn and proxySetFn respectively. Then we simply pass them to our handler and create a new Proxy to see the magic happen.

Cloning Lodash Get & Set

For the purpose of this article we will be mimicking the Get and Set functionality from Lodash by modifying the get and set handlers on the Proxy Object. Specifically, we want the ability to pass property paths like 'parent.child.grandchild', ['parent', 'child', 'grandchild'] and 'parent[child].grandchild' to our object and get (or set) the right value.

What is Lodash?

Lodash is A modern JavaScript utility library delivering modularity, performance & extras.

Lodash is a JavaScript library that makes working with object (numbers, strings, functions, arrays, etc…) extremely easy. The library is comprised of a number of tools that help developers manipulate objects in ways that are both performant and intuitive.

If you want a tried and tested library that can deliver some great functionality for working with JavaScript objects, then please use Lodash (or similar libraries).

First, Some Helper Functions

Before we start updating our proxy handlers, let’s create a few helper functions.

The first is replaceBrackets which helps us use property paths like parent[child].grandchild' by finding anything in [] (inclusive) and replacing it with the dot notation form. It uses the bracketCaptureRegex to …well… capture the brackets.

Next we have makeSegments which converts our property path into an Array of string or symbol to use in our handlers. This function uses the pathMatchRegex to test for periods and commas* in strings and the pathSplitRegex to split the matching strings into an Array.

* We are checking for commas because passing an array as the key in bracket notation forces the array into a comma delimited

Using Reflect and Recursion to Enhance Custom Handlers

The first step to creating our Lodash clone is to update our Proxy functions to use our makeSegments helper function and recursively iterate through the segments until we get/set the value.

In the proxyGetFn function we start off by testing whether or not the target exists. If it doesn’t then we return undefined. We move on to creating our segments and using the first item of the segments array as our key. and split rest into another array.

If rest has a length greater than 0, we recursively call proxyGetFn with a new target (using Reflect.get), and the rest of our segment.

Finally, we check if the target has the key using Reflect.has and return the value using Reflect.get

In the proxySetFn function we skip the check for the target and instead define our key and rest using the makeSegments helper function.

Next we check if rest has a length greater than 0. If it does, we then proceed to check if the target contains the key using Reflect.get. If that is false, we return undefined (similar to the target check in proxyGetFn). If the target does have the key, we recursively call proxySetFn (also similar to proxyGetFn)

Finally, if all is well, we can set our value!

Converting your Objects to Proxies

Our next step is to make it a easier to convert our objects to proxies. Sure you could set up a new Proxy() every time, but that would just bloat your code. Instead we can define a createProxy function that takes in an object and spits out a proxy with our custom handlers applied.

Testing Your New Proxy Object

If you’re a bit suspicious that this createProxy abstraction would just work (which you should be… don’t trust me… 👀 ) you can opt to write some tests. For your sake I’ve printed out a few to ease your mind.

We create a proxy object using createProxy and test that it returns some values. We can even add some complex property paths like complexArr.1.value and get back the right value.

Something really neat is that you can also set a value for an index that doesn’t yet exist in an array. Not that you ever would… but think about all those times where you just wanted to easily set a value at the nth index in an array dynamically and couldn’t!

Well now I… I mean you can.

Making our Lodash Clone

We’re near the end! All that’s left is to create our Lodash clone.

To do this we create a variable _ and set it to an object with get and set properties.

_.get takes in an object, a path, and a defaultValue. It then uses createProxy to create a new Proxy Object with our custom handlers. We then pass the path into the proxyObj and either return the value it finds, or the defaultValue if nothing is found.

_.set takes in an object, a path, and a value. It also creates a new Proxy object and tries to set the value to the path. If the new value is found it then mutates (really updates) the original object using structureClone**. If the new value is not found, it returns undefined.

** We use structuredClone to to update the object with the new values of the Proxy Object because proxy ≠ object.

Using our Lodash Clone Methods

If you’re a bit suspicious that this Lodash clone would just work (which you should be… don’t trust me… 👀 )(wait…) then you should definitely test it out.

Just to make things a bit easier on you I’ve logged some results below.

As you can see, we can get values with property matchers like values.0, [‘values’, 1, ‘value’] and even ‘values[1]’ which makes our _.get and _.set pretty dang close to the ones in Lodash.

I’d call this a success!

A thought exercise

Given that we’ve created get and set methods in our Lodash clone… how would you go about creating a similar omit or pick method using what you learned today?

Finally we’re Done! If you enjoyed this article or learned something new, please leave a clap or two. 👏🏾

Thanks for taking the time to read my article. Keep on the lookout for my next one:

Using the JavaScript Proxy Object as a React State Manager

Until then, I wish you all the success in the world on your next project!

--

--

Dewaun Ayers

I'm a Frontend Dev living in Melbourne, Australia and studying Computer Science. I love anything to do with web tech and am constantly trying to learn more!