A proxy looks like this:
Here we change the get function to return 37 each time a variable is not defined. First the function is created, which executes each time a property is accessed. The parameters are the object itself and the accessed property name as a string. If the property name is available the corresponding value and otherwise the default value is returned. The values set to the proxy are transparently set to the original object. A proxy cannot store values, all values are set and received from the original value. The proxy can only transform the values before setting it to the original object after receiving it from the original object.
To understand proxies you have to know these terms:
- The target is the original object which is wrapped by the proxy.
- Proxy is the new object which wraps the original object and shows the new behaviour.
- Trap is the function which is executed before the original functionality is processed and defines the new behaviour.
- Handler is the object with all traps inside.
List of Traps
The following list shows all the possibilities of traps. Implementing them is optional.
- A trap for getting property values
- A trap for setting property values
- A trap for the delete operator.
- A trap for a function call
- A trap for the new operator
- A trap for the in operator
- A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols
- A trap for Object.getPrototypeOf
- A trap for Object.setPrototypeOf
- A trap for Object.isExtensible
- A trap for Object.preventExtensions
- A trap for Object.getOwnPropertyDescriptor.
- A trap for Object.defineProperty
Copied from MDN
Something Is Changing Your Object (Set Trap)
When something is changing an object, a set trap becomes handy to identify the code spot which forces the change. Therefore, instead of returning the original object, the proxy object is returned. The proxy defines a trap for setting a property and will log the trace where the property has changed.
The return true at the end of the set trap indicates that the assignment succeeded.
Negative Array Indices (Get and Set Trap)
Negative Array indices mean counting from the end of an array instead of from the beginning. Like supported by the Array.splice method.
API Generation On The Fly (Get Trap)
In Spring Boot you can generate functions to query the database with hibernate by only creating the function declaration. This is also possible with Proxies and it feels like calling an implemented function. Here the get trap is used.
The disadvantages are that during compile time, the compiler doesn’t know which functions exist later and neither knows about the returned objects. Therefore it is hard for it to help with typings.
Proxies can not only change the behaviour of an object, they can also control the access to the object. The function Proxy.revocable returns two objects, first the proxy itself and second the revoke function.
The return value is the only difference between a Proxy.revocable and the new Proxy. It is still possible to add traps to the Proxy.
When the revoke function is called, the original object is not accessible anymore, it will be be garbage-collected. The revoke function can be called multiple times without effect.
This can be handy if the object should have controlled access only. When, as alternative, an object is set to undefined, only the pointer is removed and the object still exists.Therefore the object can be accessed by other variables which have the Object assigned.
The tpyo library makes use of the get Proxy and allows to call a method on an object even if the method call includes a typo. So for example the following is possible:
This is possible because when a property is accessed the trap checks if the property is available. If it is, the value is returned.
If the property is not available on the object, the trap reads all properties and returns the one with the lowest Levenshtein distance. See implementation here.
This maybe doesn’t make the most sense but shows the power of Proxies very well.
This is possible with the heavy use of proxies which you can see here.
This library shows the power of proxies, how they can alter the usage of objects without changing the syntax by much.
Use cases where you need proxies may be restricted but when you need to use them it is good to know they exist.