2011-08-21 11 views
29

FiddleCome annullare una chiamata Object.defineProperty?

var Assertion = function() { 
    return { "dummy": "data" };  
} 

Object.defineProperty(Object.prototype, 'should', { 
    set: function(){}, 
    get: function(){ 
    return new Assertion(this); 
    } 
}); 

// Insert magic here. 

// This needs to be false 
console.log(({}).should === undefined); 

Quali opzioni ho in ES5 per annullare una chiamata defineProperty?

Nessun suggerimento stupido come Object.defineProperty = function() { } per favore.

Il seguente Object.defineProperty(Object.prototype, 'should', {})

fa not work

e Object.defineProperty(Object.prototype, 'should', { value: undefined })

getta una Uncaught TypeError: Cannot redefine property: defineProperty nel V8

Object.defineProperty(Object.prototype, 'should', { 
    set: function() {}, 
    get: function() { return undefined; } 
}); 

getta la same error

risposta

36

In generale, non è possibile annullare una chiamata defineProperty, poiché non c'è stack di annullamento o qualcosa del genere. Il motore JS non tiene traccia dei descrittori degli attributi precedenti.

Per esempio,

Object.defineProperty(Object.prototype, 'foo', { 
    configurable: true, 
    value: 1, 
    enumerable: false 
}); 
Object.defineProperty(Object.prototype, 'foo', { 
    get: function() { 
     alert('You cannot revert me'); 
     return 2; 
    }, 
    enumerable: true 
}); 

Che cosa si può fare è rimuovere o riconfigurare un attributo, o sovrascrivere il suo valore. Come menzionato nell'altra risposta, il flag configurable deve essere true se si desidera rimuovere o riconfigurare. Una volta definita una proprietà con configurable:false, non è possibile modificare il flag configurable.


Per rimuovere un attributo (questo è presumibilmente ciò che si vuole fare), utilizzare delete:

Object.defineProperty(Object.prototype, 'foo', { 
    configurable: true, // defaults to false 
    writable: false, 
    value: 1 
}); 
delete Object.prototype.foo; 
console.log(Object.prototype.hasOwnProperty('foo')); // false 

riconfigurare utilizzare defineProperty di nuovo e passare un descrittore diversa:

Object.defineProperty(Object.prototype, 'foo', { 
    configurable: true, 
    get: ... 
    set: ... 
}); 
Object.defineProperty(Object.prototype, 'foo', { 
    value: undefined 
}); 
console.log({}.foo); // undefined 
console.log(Object.prototype.hasOwnProperty('foo')); // true 

Come mostrato in questo esempio, è possibile utilizzare defineProperty per passare da acc proprietà (get/set) e dati (value).


Per sovrascrivere, utilizzare la semplice assegnazione. In questo caso, è necessario che il flag writable sia true. Ovviamente questo non funziona con le proprietà accessorie. E lancia anche un'eccezione:

Object.defineProperty(Object.prototype, 'foo', { 
    configurable: true, 
    value: 1, 
    writable: true // defaults to false 
}); 
Object.prototype.foo = undefined; 
console.log(Object.prototype.foo); // undefined 
console.log(Object.prototype.hasOwnProperty('foo')); // true 

Object.defineProperty(Object.prototype, 'foo', { 
    get: function() { 
     return 1; 
    }, 
    writable: true // JS error! 
}); 

Nota che writable default false quando si utilizza defineProperty, ma true quando si utilizza la sintassi semplice o.attr = val; per definire una proprietà (prima non esistenti).

+0

qualcuno può spiegare perché non possiamo sovrascrivere o rimuovere un 'accessorio' assegnando un nuovo valore alla proprietà come questo 'obj.foo =' nuovo valore '; '? in altre parole, perché dobbiamo eliminare prima la proprietà o riconfigurarla per sbarazzarci di tale accessor – kapreski