Following code contains proxy with get
trap in object's __proto__
. When getting some property from the object, according to js logic, trap is called only when object itself doesn't contain corresponding property. So after assignment the property appears in the object and get trap is not called. It workes exactly as I want.
var x = Object.create(new Proxy({}, {
get(obj, key) {
if (typeof key !== 'symbol') {
console.log('Reading a nonexisting property: ' + key);
}
}
}));
var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a;
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
temp = x.a;
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
x.a = 12;
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a;
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }
Now I'm adding a set
trap:
var x = Object.create(new Proxy({}, {
get(obj, key) {
if (typeof key !== 'symbol') {
console.log('Reading a nonexisting property: ' + key);
}
},
set(obj, key, val, receiver) {
console.log('Assigning a property: ' + key);
Reflect.set(obj, key, val); // Inside of proxy, not outside
//Reflect.set(receiver, key, val); // Infinite recursion
return true;
}
}));
var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a;
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
temp = x.a;
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
x.a = 12;
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a;
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }
The problem is that I can't write a property directly to the object. The property is either written to the object which is wrapped by proxy instead of object that wraps the proxy or infinite recursion of set
trap occurs.
So I want to get the same output as in the first snippet, but with new line Assigning a property: a
.
To actually create a property, you will have to use Object.defineProperty
(or Reflect.defineProperty
, if you prefer). Just setting the property through assignment or Reflect.set
will indeed traverse the prototype chain, so when you do this to an object in a setter on its prototype (or a proxy trap), you always get recursion indeed.
You can use
new Proxy({}, {
get(target, key) {
if (typeof key !== 'symbol') {
console.log('Reading a nonexisting property: ' + key);
}
},
set(target, key, val, receiver) {
console.log('Assigning a property: ' + key);
return Reflect.defineProperty(receiver, key, {
value: val,
writable: true,
enumerable: true,
configurable: true
});
}
});
Full code:
var x = Object.create(new Proxy({}, {
get(obj, key) {
if (typeof key !== 'symbol') {
console.log('Reading a nonexisting property: ' + key);
}
},
set(obj, key, val, receiver) {
console.log('Assigning a nonexisting property: ' + key);
return Reflect.defineProperty(receiver, key, {
value: val,
writable: true,
enumerable: true,
configurable: true
});
}
}));
var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a; // get trap
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
temp = x.a; // get trap
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
x.a = 12; // set trap creates a property and sets it
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a; // direct read - no traps
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
x.a = 42; // direct write - no traps
console.log(6, Object.prototype.hasOwnProperty.call(x, 'a'));
temp = x.a; // direct read - no traps
console.log(7, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }