Le 28/04/2011 10:32, Andreas Gal a écrit :
On Apr 28, 2011, at 1:26 AM, David Bruant wrote:
Le 27/04/2011 23:09, Sean Eagan a écrit :
As explained before, the existing ES5 semantics would cause the proxy's
"getPropertyDescriptor" trap to be called thus obtaining any "getter"
/ "setter" that the proxy wants. The |this| binding of this "getter"
/ "setter" will then be set to the "receiver" by ES5 8.12.3 step 13
for a "getter" or ES5 section 8.12.5 step 5.b for a "setter". The
proxy's "get" / "set" trap would not get called, and thus would not
need the "receiver" arguments.
Interesting. What you're saying is that if a proxy in on the prototype chain, then its
"set" and "get" traps are never called by a get or set on the base object.
In any case, in any example we could write, the |this| binding is correct not
because of the get/set trap on the prototype chain, but because of the |this|
binding that is performed at the own layer level.
I think you're right on removing the receiver argument.
It should be noted that on that page [1] there is a consensus that a receiver
argument should be added to all proto-climbing traps. I don't think we've had
the explanation of this point yet. If I recall correctly, this necessity was
raised by Andreas Gal (CC'ed). SpiderMonkey-related bug [2]
Actually we are still going back and forth on this. Proto-climbing might be the wrong
selector here. "Can call a getter or setter" seems to be the better category,
and that would be only get and set. get and set definitely do need the receiver though.
If you have a proxy on the proto chain and you don't find what you are looking for in the
direct object, the next step is invoking get on the prototype (proxy), and you need the
proper receiver if you have to call a getter (the direct object, not the proxy).
Sean's point is that, as per ES5, in the case you are describing the
prototype climbing doesn't occur with the get/set trap on the prototype
object, but rather with getPropertyDescriptor (ES5 - 8.12.3 step 8
(which is the first step of the algorithm. Wrong numbering)). The |this|
binding then occurs during the get/set call of the base object.
According to ES5, the following example should throw an error:
---
var handler = {
has: function (name) {
return name == 'foo';
},
get: function (rcvr, name) {
if (name != 'foo')
return undefined;
print(proxy !== rcvr);
return "bye";
},
};
var proxy = Proxy.create(handler);
var c = Object.create(proxy);
print(c.foo);
---
As per ES5, "c.foo" should call c.[[Get]] (1) which should call
c.[[GetProperty]] (2). This call should fail at finding "foo" at the own
layer and should recursively call proxy.[[GetProperty]] (3) (not
proxy.[[Get]] ! The example should throw an error, because handler
doesn't have a getPropertyDescriptor trap to reify
proxy.[[GetProperty]]). When the property descriptor is found and
returned from (3), it is returned to (2) then to the c.[[Get]] call (1).
If the property descriptor happened to be an accessor descriptor, then
the |this| binding should be perfomed at the end of (1) where c.[[Get]]
is called and where there is no need to leak the c object (misnumbered
11-13 steps of ES5 - 8.12.3).
As a consequence of the call sequence I have described, Sean's point is
that there is actually no need for a receiver argument even in get and
set traps.
Cheers,
David
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss