Proxy forwarding handlers and accessor properties

David Bruant david.bruant at labri.fr
Thu Jun 16 17:20:17 PDT 2011


Le 17/06/2011 01:54, David Flanagan a écrit :
> With ordinary objects, methods and property getter functions are both
> invoked on the object itself.  If this object is proxied with
> Proxy.Handler, however, the property getter function will be invoked
> on the original object and the method will be invoked on the proxy
> object.  The code below demonstrates.
>
> I find this surprising, though I'm not sure whether it constitutes a
> bug in Proxy.Handler.  I do think it is at least a reason why the
> receiver argument to get() is necessary and should not be removed as
> proposed by
> http://wiki.ecmascript.org/doku.php?id=strawman:proxy_drop_receiver
>
> The code that demonstrates this is below.  It runs in the current
> Firefox Aurora. I have actually been affected by this issue when the
> proxy object is stored in a WeakMap but the object it is forwarding to
> is not in the WeakMap.
>
>     David Flanagan
>
>
> if (this.console) print = console.log.bind(console);
>
> // An object with an accessor property and a method.
> var o = {
>     get property() { return map.get(this); },
>     method: function() { return map.get(this); }
> };
>
> var map = new WeakMap();
> map.set(o, "o");
>
> // Both the getter function and method are invoked on o
> print(o.property);         // prints "o"
> print(o.method());         // prints "o"
>
> // This works for inherited properties and methods, too
> var p = Object.create(o);
> map.set(p, "p");
> print(p.property);        // prints "p"
> print(p.method());        // ditto
>
>
> // When we create a proxy with a forwarding handler, though, the this
> value
> // is different in the two cases.
> var handler = {
>     target: o,
>     get: function(receiver, name) {
>         return this.target[name];  // Same as Proxy.Handler.prototype.get
>     }
> }
If you get rid of the "get" trap (you need a getOwnPropertyDescriptor
trap though), the default get (derived) trap will be called instead and
basically do what you do afterward (call to getOwnPropertyDescriptor
trap which will call Object.getOwnPropertyDescriptor(this.target,
name)+d.get.call(receiver)). The 'this' binding is performed by the
engine (with the receiver as value) after the property descriptor has
been returned (as explained in strawman:proxy_drop_receiver).

I've come across a similar issue (it was a set VS defineProperty issue,
but basically used the same solution). One suggested solution is written
down on the wiki at strawman:derived_traps_forwarding_handler

Cheers,

David
>
> var q = Proxy.create(handler);
> map.set(q, "q");
> print(q.property);   // Prints "o"
> print(q.method());   // Prints "q"
>
> // In order to invoke the getter function on the same object as the
> method
> // we have to go to more trouble and use code that is probably much
> slower.
> // And, we need that first receiver argument.
> var handler2 = {
>     target: o,
>     get: function(receiver, name) {
>         var d = Object.getOwnPropertyDescriptor(this.target, name);
>         if (d.value) return d.value;
>         else return d.get.call(receiver);
>     }
> };
>
> var r = Proxy.create(handler2);
> map.set(r, "r");
> print(r.property);   // Prints "r"
> print(r.method());   // Prints "r"



More information about the es-discuss mailing list