Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
123 views
in Technique[技术] by (71.8m points)

javascript - How do I undo a Object.defineProperty call?

Fiddle

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

What options do I have in ES5 to undo a defineProperty call ?

No silly suggestions like Object.defineProperty = function() { } please.

The following Object.defineProperty(Object.prototype, 'should', {})

does not work

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

Throws a Uncaught TypeError: Cannot redefine property: defineProperty in V8

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

Throws the same error

delete Object.prototype.should also does not work

question from:https://stackoverflow.com/questions/7141210/how-do-i-undo-a-object-defineproperty-call

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In general, you can't undo a defineProperty call, since there's no undo stack or something. The JS engine does not keep track of previous attribute descriptors.

For example,

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

What you can do is remove or reconfigure an attribute, or overwrite its value. As mentioned in the other answer, the configurable flag is required to be true if you want to remove or reconfigure. Once a property is defined with configurable:false, you cannot change the configurable flag.


To remove an attribute (this is supposedly what you want to do), use 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

To reconfigure, use defineProperty again and pass a different descriptor:

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

As shown in this sample, you can use defineProperty to switch between accessor (get/set) and data (value) properties.


To overwrite, use simple assignment. In this case, you need the writable flag to be true. Obviously this does not work with accessor properties. It even throws an exception:

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

Note that writable defaults to false when you use defineProperty, but true when you use the simple syntax o.attr = val; to define a (previously not existing) property.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...