Alert Message
Thanks for signing up! We hope you enjoy our newsletter, The Teller.
Reflect and Proxy 
engineering

Metaprogramming with Reflect and Proxy in Javascript

By Jack Anderson

Metaprogramming is a powerful tool in any language. With the advent of ES6 and the addition of Reflect and Proxy objects, there are now even more options to enable dynamic behavior in your code.

So What Is Metaprogramming?

At its core, metaprogramming is simple—it just means programs that can write programs. Think of it as code that can change itself, or other code, while running.

As you could imagine, metaprogramming is very powerful, but can also be very dangerous if implemented without care.

Why would you use metaprogramming?

  1. Changing the behavior of code you don’t control—for example, adding logging, validation, or other utility code to a third party library.
  2. Making a program more flexible—for example, adding in backward compatibility, or instituting a switch based on a variable set at runtime.

Why shouldn’t you use metaprogramming?

  1. Metaprogramming is a complicated solution. Simple solutions are better 95% of the time.
  2. Metaprogramming obfuscates the code flow—sometimes it’s hard to know what is being run just by looking at the code. It might take debugging and stepping through the code just to figure out what it does.
  3. You can’t rely on using ES6.
  4. You need to run the code in Internet Explorer.

With the ‘why’ in mind, let’s dive into the ‘how’ by taking a look at JavaScript’s new objects.

Reflect

Reflection is a crucial part of metaprogramming. It allows for access to an object and its methods and attributes at runtime.

For example, we might have some object const obj = { x: 1 };

Using conventional programming, we might run the following code:

Using Reflect we might run it this way:

Reflect has corresponding methods for any object access methods, as well as methods for calling functions as well.

If you’re thinking that that just looks more verbose and awkward, you’re right. Remember what we said about meta programming being a complicated solution? That said, there are some rare instances where it’s indispensable.

Cases where Reflect might be the best choice:

  • Use alongside the Proxy object.
  • Cases where you might be setting or applying a dynamic attribute—where you don’t necessarily know what you’ll be asking for until runtime.

Proxy

The Proxy object is a way to intercept or ‘trap’ fundamental behavior on JavaScript objects. These traps provide an entry point into an action to inspect or even redefine behavior.

The Proxy object takes two arguments. 1: the target, which is the object we want to inspect. 2: the handler which is a collection of traps. The supported traps include set, which intercepts behavior to change a property on the object, get, which intercepts access of a property, apply which will intercept function calls, and others.

If you’re thinking to yourself, “Proxy methods share their names with a lot of Reflect methods,” you’re exactly right. While there may be some subtle differences, Proxy and Reflect mirror each other closely.

Examples where Proxy is useful:

  • You need to augment existing behavior on an object—adding validation, modifying access to fields, etc.
  • You need to redirect code based on some variable that is determined at runtime.

Putting It Together

Have you ever logged out the contents of an object in 47 different places in your code, trying to see where object.foo got changed from bar to baz? Worse still, does that object get mutated in some third party code stashed away in node_modules? I know I have, at least twice in the last six months alone.

Here’s an example of a method using both Proxy and Reflect that will log changes to the fields of an object:

Note that it uses the set trap on Proxy to listen for any changes to properties, and then uses Reflect to actually apply those changes.

You can see how this might be useful in other cases—you could instead do validation in that handler, and only return the Reflection when validation passes. Since you can call attachProxy with any object, you can even use it on third party code, like lodash . That said, you must be able to replace the object reference with a reference to the proxy, which is a very clear limitation.

Here’s the method in action:

If you want to talk about metaprogramming or learn more about the Earnest Eng team, we are hiring!

Disclaimer: This blog post provides personal finance educational information, and it is not intended to provide legal, financial, or tax advice.