2011-08-21 184 views
29

Fiddle如何撤消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); 

我有什么选择在ES5撤消defineProperty电话吗?

请不要愚蠢的建议,如Object.defineProperty = function() { }

以下Object.defineProperty(Object.prototype, 'should', {})

确实not work

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

抛出在V8 Uncaught TypeError: Cannot redefine property: defineProperty

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

抛出same error

delete Object.prototype.shoulddoes not work

回答

36

通常,您不能撤消defineProperty调用,因为没有撤消堆栈或其他东西。 JS引擎不跟踪以前的属性描述符。

例如,

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 
}); 

你可以做的是删除重新配置属性或覆盖它的价值。正如在其他答案中提到的那样,如果要删除或重新配置,configurable标志必须为true。 一旦使用configurable:false定义了一个属性,就不能更改configurable标志。


要删除属性(推测这是你想要做什么),使用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 

要重新配置,再次使用defineProperty,并通过不同的描述:

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 

如本示例所示,您可以使用defineProperty在acc essor(get/set)和数据(value)属性。


要覆盖,请使用简单的赋值。在这种情况下,您需要writable标志为true。显然这不适用于访问器属性。它甚至抛出一个异常:

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! 
}); 

注意writable默认为当您使用definePropertyfalse,但true当您使用简单的语法o.attr = val;定义(以前不存在)属性。

+0

任何人都可以解释为什么我们不能通过赋予像这样的属性的新值来覆盖或移除一个'accessor'; obj.foo ='new value';'?换句话说,为什么我们必须首先删除属性或重新配置它以摆脱该访问器 – kapreski