3

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
0

1 Answer 1

4

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.