直接设置JavaScript的属性特性而不使用Object.defineProperty方法

3

我知道正确设置Javascript属性特性的方法是使用Object.defineProperty函数,但我很好奇为什么不能直接在通过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}

如上代码所示,在查看 a.x 原始描述符对象的 'writable' 属性时,该属性是可写和可配置的,这意味着设置属性描述符的 'writable' 属性并没有改变底层的 x 属性。因此,我不确定为什么不能只写:
Object.getOwnPropertyDescriptor(a, 'x').writable = false
1个回答

4

这是因为每次使用 Object.getOwnPropertyDescriptor 时,FromPropertyDescriptor 都会构建一个新的不同对象。

该对象没有特殊的设置器,因此更改其数据不会影响原始对象的属性。

相反,您应该重新定义该属性:

var desc = Object.getOwnPropertyDescriptor(a, 'x');
desc.writable = false;
Object.defineProperty(a, 'x', desc);

否则,你可以构建自己的API,类似于这样的东西。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接