web-dev-qa-db-ja.com

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

defineProperty呼び出しを取り消すためにES5にはどのようなオプションがありますか?

Object.defineProperty = function() { }のようなばかげた提案はしないでください。

次のObject.defineProperty(Object.prototype, 'should', {})

します 動作しません

および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; }
});
_

同じエラー をスローします

_delete Object.prototype.should_も 機能しません

36
Raynos

一般に、元に戻すスタックなどがないため、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を使用して、アクセサー(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を使用する場合はfalseがデフォルトでdefinePropertyになりますが、単純な構文o.attr = val;を使用して(以前は存在しなかった)プロパティを定義する場合はtrueであることに注意してください。

41