Reputation: 484
I know that the proper way to set Javascript property attributes is to use the Object.defineProperty function, but I am curious what is preventing the setting of these values directly on the descriptor object that is returned via Object.getOwnPropertyDescriptor.
var a = new Object()
a.x = 1
var attributes = Object.getOwnPropertyDescriptor(a, 'x') //Object {value: 1, writable: true, enumerable: true, configurable: true}
var attributesOfWritable = Object.getOwnPropertyDescriptor(attributes, 'writable') //Object {value: true, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(a, 'x').writable = false
console.log(Object.getOwnPropertyDescriptor(a, 'x')) //Object {value: 1, writable: true, enumerable: true, configurable: true}
Object.defineProperty(a, 'x', {writable: false})
console.log(Object.getOwnPropertyDescriptor(a, 'x')) //Object {value: 1, writable: false, enumerable: true, configurable: true}
As shown in the code above, when looking at the descriptor object returned for the 'writable' property on the original descriptor object for a.x, the property is writable and configurable, which means setting the writable
property of the property descriptor didn't change the underlying x
property.
So I am unsure why I cannot just write:
Object.getOwnPropertyDescriptor(a, 'x').writable = false
Upvotes: 3
Views: 467
Reputation: 288550
That's because each time you use Object.getOwnPropertyDescriptor
, FromPropertyDescriptor builds a new different object.
That object has no special setters, so altering its data won't affect the properties of the original object.
Instead, you should redefine the property:
var desc = Object.getOwnPropertyDescriptor(a, 'x');
desc.writable = false;
Object.defineProperty(a, 'x', desc);
Otherwise, you could build you own API, something like this
var getLiveDescriptor = (function() {
var map = new WeakMap(),
getDesc = Object.getOwnPropertyDescriptor;
return function getLiveDescriptor(obj, prop) {
var descriptors = map.get(obj);
if(!descriptors) map.set(obj, descriptors=Object.create(null));
var descriptor = descriptors[prop];
if(descriptor) return descriptor;
return descriptors[prop] = new Proxy({}, {
has(target, key) {
return key in getDesc(obj, prop);
},
get(target, key, receiver) {
return getDesc(obj, prop)[key];
},
set(target, key, value, receiver) {
var desc = getDesc(obj, prop);
desc[key] = value;
Object.defineProperty(obj, prop, desc);
return true;
},
ownKeys(target) {
return Object.getOwnPropertyNames(getDesc(obj, prop));
}
});
};
})();
Object.getOwnPropertyDescriptor(a, 'x').writable; // true
getLiveDescriptor(a, 'x').writable = false;
Object.getOwnPropertyDescriptor(a, 'x').writable; // false
Upvotes: 4