Le 18/09/2013 14:28, Tom Van Cutsem a écrit :
2013/9/17 Jason Orendorff <[email protected]
<mailto:[email protected]>>
If that's all, it seems like we should definitely remove [[Invoke]]
and the .invoke trap. The MOP was already complicated enough. The
performance argument is a non-starter, and the other "feature" is
entirely undesirable.
I'm trying to reconstruct Allen's motivation for including [[Invoke]],
which had to do with proxies that forward method calls to target
objects that depend on their this-binding to access private state.
Assume that we want to proxy the following target object:
var privateState = new WeakMap();
var target = { m: function() { return privateState.get(this); };
privateState.set(target, 42);
assert( target.m() === 42 );
// I need otherTarget to make a point later
var otherTarget = {};
privateState.set(otherTarget, 43);
assert( target.m.call(otherTarget) === 43 ); // we can still re-bind
|this|
Now consider a naive forwarding proxy, written as:
var p1 = new Proxy(target, {
get: function(target, name, receiver) {
return target[name];
}
});
Now: p1.m() === undefined // bad, because |this| inside target.m is
bound to proxy instead of target.
But: p1.m.call(otherTarget) === 43 // good, clients can still rebind
|this|.
To solve the first problem, the proxy can be refined to eagerly bind
any method properties:
var p2 = new Proxy(target, {
get: function(target, name, receiver) {
var prop = target[name];
if (typeof prop === "function") return prop.bind(target);
return prop;
}
});
Now: p2.m() === 42 // good
But: p2.m.call(otherTarget) !== 43 // bad, cannot re-bind |this| on
extracted properties
Adding an invoke() trap gives us a way to solve this:
var p3 = new Proxy(target, {
get: function(target, name, receiver) {
return target[name]; // no bind-on-extraction
},
invoke: function(target, name, args, receiver) {
return target[name].apply(target, args);
}
});
Now: p3.m() === 42 // good
And: p3.m.call(otherTarget) === 43 // good
I guess we could indeed drop the invoke() trap, if we are willing to
use the following, more intricate, pattern:
var p4 = new Proxy(target, {
get: function(target, name, receiver) {
var prop = target[name];
if (typeof prop === "function") {
return function(...args) {
var self = (this === p4 ? target : this); // re-bind |this|
only if bound to the proxy, otherwise don't rebind
return prop.apply(self, args);
}
}
return prop;
}
});
Now: p4.m() === 42 // good
And: p4.m.call(otherTarget) === 43 // good
AFAICT, performance arguments aside, the question of whether or not to
include invoke() boils down to whether you prefer the p3 or p4 pattern.
An alternative to p3 and p4 would be to find a solution for the
interaction between private state and proxies that also works with:
Date.getMonth.call(myProxy)
A way that would make p1 work in essence (which very naturally you
listed as the first idea ;-) ).
Such a solution would also make invoke unnecessary.
David
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss