【问题标题】:How do I undo a Object.defineProperty call?如何撤消 Object.defineProperty 调用?
【发布时间】:2011-10-31 18:09:39
【问题描述】:

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

我在 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.should 还有does not work

【问题讨论】:

    标签: javascript google-chrome node.js defineproperty


    【解决方案1】:

    一般来说,您无法撤消 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!
    });
    

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

    【讨论】:

    • 谁能解释为什么我们不能通过为obj.foo = 'new value'; 这样的属性分配一个新值来覆盖或删除accessor ?换句话说,为什么我们必须先删除该属性或重新配置它以摆脱该访问器
    • @kapreski 因为 JavaScript 访问器属性不能以允许重新分配属性本身的方式工作:当您尝试为访问器分配值时,正确编程的 JavaScript 引擎将“捕获”调用如果已定义,则将分配的值传递给访问器的 setter 函数,否则它假定根本不应该写入该属性并将引发错误,如根据 ECMAScript 规范。将属性定义为访问器将删除默认的 [[Get]][[Set]] 行为,以支持用户提供的行为。
    猜你喜欢
    • 1970-01-01
    • 2021-06-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 2014-11-06
    • 1970-01-01
    • 2018-10-25
    相关资源
    最近更新 更多