2016-05-16 66 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