I'd like to first give an answer to the implicit question "Why do some traps have a receiver and others don't?". See here for a list of all traps. I was at first missing myself a reference to the receiver within some of these functions. But the logic is as follows: All these traps are interceptors for functions that exist independently from the Proxy
: the object internal methods which are invoked whenever an interaction with an object takes place. These internal methods have been made accessible via the static functions of the namespace Reflect
. These static functions have the same arguments as those of the proxy handler, yet they are meaningful without a proxy (even though apparently the Reflect
API was designed having proxies in mind, i.e. making the internal methods available to the proxy). Each of these functions has as many arguments as it needs to perform what it does (without any proxy around). Adding an additional receiver
argument to Reflect.apply
would be meaningless without a proxy around as one already passes a thisArg
for the function application. On the other hand, Reflect.get
gets the getter for a property of an object and then applies it - usually with the object itself as this
, but one might want to replace this
by any other object (in particular in the case of a prototype chain, where the getter of a prototype is applied to a descendant). Therefore the extra argument receiver
makes sense even without a proxy around.
And as @Bergi pointed out in the comments, even where present as argument in a trap function, the receiver
isn't necessarily identical to the proxy anyway, but is simply the this
of a getter or setter in this context, so can be a prototype descendant of a proxy or even something completely different. To understand the latter, consider the following:
If one calls the Reflect
functions with a proxy as the target
argument, this leads to a call of the corresponding trap function with the proxy replaced by the target of the proxy. E.g. the call Reflect.get(proxy, 'value', exoticObject)
will lead to a call of handler.get
with proxy
replaced by the target of the proxy (let's call it proxyTarget
) but the other arguments unchanged, i.e.: handler.get(proxyTarget, 'value', exoticObject)
. So in this example, the receiver is not even related to the proxy.
Now for the question how to access the proxy from within the traps: One possibility is to create a specific handler for each proxy and store a reference to the proxy as property of the handler. The handler is always accessible within the traps via "this". So this.proxy
would give you the proxy within each of the trap functions.
The OPs question mentions also an extension object with supplemental properties and a WeakMap to obtain it. Instead of using the proxy to look up the extension in the WeakMap one could alternatively as well save a reference to the extension in the handler and access it via this.extension
in the traps.