Reflect and Proxy in JavaScript
/ 5 min read
Reflect
There is a song called “Reflection” in Disney’s version of Mulan. Mulan looks at her reflection in the water, contemplating her future choices. The lyrics and visuals of the song contain both meanings of the word “reflection”:
- Reflection as in “to reflect” or “to mirror”
- Reflection as in “to contemplate” or “to introspect”
Translating Reflect as “反射” (reflection) in programming can indeed be confusing. In fact, it should lean towards the direction of “self-reflection” or “introspection”. Reflect is one of the important methods in JavaScript metaprogramming. Metaprogramming allows you to achieve the desired functionality from a higher dimension, such as adjusting the original behavior of a program, invoking internal methods, or writing code programmatically. Of course, Reflect is not an exclusive term in JavaScript; other languages like Go and Java also have Reflect methods.
JavaScript’s Reflect has the following methods:
Reflect.apply()
Reflect.construct()
Reflect.defineProperty()
Reflect.deleteProperty()
Reflect.get()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.has()
Reflect.isExtensible()
Reflect.ownKeys()
Reflect.preventExtensions()
Reflect.set()
Reflect.setPrototypeOf()
Seeing this bunch of stuff, I can’t help but exclaim, familiar, too familiar. It seems like I’ve used many of these methods somewhere before. Indeed, Reflect
intentionally moved some methods that were hanging on Object
and Function
over here.
This brings the first obvious benefit of using Reflect, simplified code. In addition, apply
actually calls the internal method [[Call]]
of the JavaScript engine, so Reflect falls into the category of metaprogramming.
For example, Reflect.ownKeys
takes on the functionality of Object.getOwnPropertyNames
to inspect the properties of an object:
Methods like Reflect.deleteProperty()
and Reflect.has()
take on the functionality of some operators:
In methods like get
and set
, as before, the internal methods [[Get]]
and [[Set]]
are called:
But this becomes confusing. object1.x
also calls the internal method [[Get]]
, and it’s even simpler. Why use the cumbersome method Reflect.get
? The answer is to work with Proxy
.
Proxy
Proxy
is easy to understand, and I believe everyone has often seen this word in certain fields (dog head). Here, it also means that it is a proxy. A Proxy
instance is an object, and your operations on this object will be proxied by other functions.
The most basic Proxy
looks like this:
In fact, nothing will happen with this Proxy
, everything will remain the same. If you want something to happen, you can work with the handler
.
You can see that proxyFactory
needs to pass in a traps
list. When the function runs, it puts the trap
into the handler
, and then new Proxy(target, handler)
is used to operate the object using the trap
as a proxy.
So what is a trap
? It can be considered as a “trap” that allows certain operations to “fall into” this “trap” and directly execute the trap function.
According to the definition on MDN, a trap is a function that defines the behavior for the corresponding object internal method. This concept is analogous to traps in operating systems.
Based on this definition, traps perfectly align with the functionality of Reflect
. In fact, the method names of Reflect
are exactly the same as the names of the traps. Therefore, we can set it up like this:
With this setup, the test
object will log when you make any internal method calls. For example:
In this example, we are just printing out the operations and parameters. In reality, you can perform any desired operations on the object within the trap
. This opens up a wide range of programming possibilities. For example, Vue 3’s reactivity principle is closely tied to Reflect
and Proxy
.
Takeaway
Reflect
is an important object for JavaScript metaprogramming. It allows you to call internal methods of objects and perform internal operations on them.Reflect
makes functions likeFunction.prototype.apply.call
andObject.getOwnPropertyNames
more intuitive and concise.Reflect
takes on the functionality of operators likein
and returns the operation results.Reflect
can be perfectly combined withProxy
to define object behavior arbitrarily.