Yes, this is possible in ES2015+, using the Proxy. It's not possible in ES5 and earlier, not even with polyfills.
It took me a while, but I finally found my previous answer to this question. See that answer for all the details on proxies and such.
Here's the proxy example from that answer:
const obj = new Proxy({}, {
get: function(target, name, receiver) {
if (!(name in target)) {
console.log("Getting non-existant property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set: function(target, name, value, receiver) {
if (!(name in target)) {
console.log("Setting non-existant property '" + name + "', initial value: " + value);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);
obj.foo = "baz";
console.log("[after] obj.foo = " + obj.foo);
Live Copy:
"use strict";
const obj = new Proxy({}, {
get: function(target, name, receiver) {
if (!(name in target)) {
console.log("Getting non-existant property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set: function(target, name, value, receiver) {
if (!(name in target)) {
console.log("Setting non-existant property '" + name + "', initial value: " + value);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);
obj.foo = "baz";
console.log("[after] obj.foo = " + obj.foo);
When run, that outputs:
Getting non-existant property 'foo' [before] obj.foo = undefined Setting non-existant property 'foo', initial value: bar [after] obj.foo = bar [after] obj.foo = baz