Do I have to replace some object by its proxy everywhere in the code, i.e. no way to debug pre-existing code as-is and immediately?
That might be easiest, but it isn't the only option.
If you know exactly which object, i.e. you have a reference to it, you can replace its property with a getter/setter:
const obj = { abc: 123 };
function watchProperty(obj, key) {
const desc = Object.getOwnPropertyDescriptor(obj, key);
let value = desc.value;
Object.defineProperty(obj, key, {
enumerable: desc.enumerable,
get() {
console.log('GET', key);
if (desc.writable === undefined) {
if (desc.get) return desc.get.call(obj);
return undefined;
} else {
return value;
}
},
set(val) {
console.log('SET', key, val);
if (desc.writable === undefined) {
if (desc.set) desc.set.call(obj, val);
} else if (desc.writable) {
value = val;
}
},
});
}
watchProperty(obj, 'abc');
console.log('obj.abc:', obj.abc);
obj.abc = 456;
console.log('obj.abc:', obj.abc);
Based on the ECMAScript 2022 specification.
Mind that to be able to use Object.defineProperty
, the object shouldn't already have that property defined with configurable
set to false
. Luckily, this only happens if Object.defineProperty
was used in the first place.
I used Object.getOwnPropertyDescriptor
and made the property behave obj
-specific. If your object has an inherited property, you'd have to change it in the prototype chain, but with my implementation of watchProperty
that would lead to some weird interactions since value
and obj
are obj
-specific.
That also brings me to another point: if you want to watch an (or every) instance of a class, you can watch the property on the prototype.