2016-05-16 77 views
2

我知道设置Javascript属性属性的正确方法是使用Object.defineProperty函数,但我很好奇什么能够防止这些值直接在描述符对象上设置通过Object.getOwnPropertyDescriptor返回。直接设置Javascript属性属性而不是Object.defineProperty

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} 

如在上面的代码中所示,在看该描述符用于斧原始描述符对象上的“可写”属性对象返回的情况下,属性是可写的和可配置的,这意味着设置的所述writable属性属性描述符没有改变底层的x属性。

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

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

回答

3

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

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

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

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