According to MDN,
handler.set()
can trap Inherited property assignment:
Object.create(proxy)[foo] = bar;
In which case, how does one both monitor and allow local assignments on inherited objects?
var base = {
foo: function(){
return "foo";
}
}
var proxy = new Proxy(base, {
set: function(target, property, value, receiver){
console.log("called: " + property + " = " + value, "on", receiver);
//receiver[property] = value; //Infinite loop!?!?!?!?!
//target[property] = value // This is incorrect -> it will set the property on base.
/*
Fill in code here.
*/
return true;
}
})
var inherited = {}
Object.setPrototypeOf(inherited, Object.create(proxy));
inherited.bar = function(){
return "bar";
}
//Test cases
console.log(base.foo); //function foo
console.log(base.bar); //undefined
console.log(inherited.hasOwnProperty("bar")) //true
After some additional thought, i noticed that it intercepts 3 ops:
Property assignment: proxy[foo] = bar and proxy.foo = bar
Inherited property assignment: Object.create(proxy)[foo] = bar
Reflect.set()
but not Object.defineProperty()
which appears to be even lower level than the = operator.
Thus the following works:
var base = {
foo: function(){
return "foo";
}
};
var proxy = new Proxy(base, {
set: function(target, property, value, receiver){
var p = Object.getPrototypeOf(receiver);
Object.defineProperty(receiver, property, { value: value }); // ***
return true;
}
});
var inherited = {};
Object.setPrototypeOf(inherited, Object.create(proxy));
inherited.bar = function(){
return "bar";
};
// Test cases
console.log(base.foo); // function foo
console.log(base.bar); // undefined
console.log(inherited.bar); // function bar
console.log(inherited.hasOwnProperty("bar")) // true
I see two options (maybe):
Store the property in a Map
, keeping the Map
s for various receivers in a WeakMap
keyed by the receiver. Satisfy get
by checking the Map
and returning the mapping there instead of from the object. (Also has
.) Slight problem is that you also need to proxy the receiver (not just base
) in order to handle ownKeys
. So this could be unworkable.
Temporarily get the proxy out of the inheritance chain while setting.
Here's that second one:
var base = {
foo: function(){
return "foo";
}
};
var proxy = new Proxy(base, {
set: function(target, property, value, receiver){
const p = Object.getPrototypeOf(receiver); // ***
Object.setPrototypeOf(receiver, null); // ***
receiver[property] = value; // ***
Object.setPrototypeOf(receiver, p); // ***
return true;
}
});
var inherited = {};
Object.setPrototypeOf(inherited, Object.create(proxy));
inherited.bar = function(){
return "bar";
};
// Test cases
console.log("base.foo:", base.foo); // function foo
console.log("base.bar:", base.bar); // undefined
console.log("inherited.bar:", inherited.bar); // function bar
console.log("inherited has own bar?", inherited.hasOwnProperty("bar")); // true