直接设置Javascript属性属性而不是Object.defineProperty

时间:2016-05-16 14:28:33

标签: javascript

我知道设置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}

如上面的代码所示,当查看为ax的原始描述符对象上的'writable'属性返回的描述符对象时,该属性是可写和可配置的,这意味着设置writable属性属性描述符未更改基础x属性。

所以我不确定为什么我不能写:

Object.getOwnPropertyDescriptor(a, 'x').writable = false

1 个答案:

答案 0 :(得分:4)

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

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

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

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

否则,您可以构建自己的API,类似这样的

{{1}}