在prototype(Object.defineProperty)上设置只读属性时没有异常

时间:2013-01-24 06:22:49

标签: javascript strict-mode

我在对象上创建了一个只读属性,并进行了相应的单元测试。

//works as expected
function OnSelf() {
    this._val = 'test';
    Object.defineProperty(this, 'test', {
        enumerable: true,
        configurable: false,
        get: function () {
            return this._val;
        }
    });
} 

然而,我意识到我应该将readonly属性放在原型而不是每个单独的实例上。我改变了我的代码,然后我的一个测试失败了。

//no exception when trying to delete the property
function OnPrototype() {
    this._val = 'test';

}
Object.defineProperty(OnPrototype.prototype, 'test', {
    enumerable: true,
    configurable: false,
    get: function () {
        return this._val;
    }
});

当删除原型上的只读属性时,似乎不会抛出异常,但是当属性在对象上时,会抛出异常。

var s = new OnSelf();
delete s.test; // throws error

var p = new OnPrototype();
delete p.test; // doesn't delete it, but no error occurs

我创建了http://jsfiddle.net/pdgreen/3BGfM/来证明问题。我在Mac上使用chrome和firefox确认了相同的行为。

这是正确的事吗?为什么如果属性在对象上,抛出异常,但在原型上,没有异常?这让我感到惊讶。谁能解释为什么会这样呢?

2 个答案:

答案 0 :(得分:4)

这是你所看到的正确行为。 'delete'关键字只删除对象自己的属性;它无法删除对象的原型属性。 (如果确实如此,那将是非常糟糕的 - 它会搞砸从同一原型继承的任何其他对象!)

尝试以下方法:

> function Constructor() {}
undefined
> Constructor.prototype.test = "Prototype";
"Prototype"
> var obj = new Constructor();
undefined
> obj.test
"Prototype"
> obj.test = "Child"
"Child"
> obj.test
"Child"
> delete obj.test
true
> obj.test
"Prototype"

原型继承的关键是原型是包含自己属性的实际对象,并且继承是完全实时和动态的。如果对象没有定义属性但其原型链中的对象确实存在,则子对象继承该值。当它的值在本地被覆盖时,它现在定义了该属性本身。如果子对象的属性被删除,原型中的值将再次出现。

答案 1 :(得分:1)

当直接在对象上定义属性时,该对象具有可以删除的“自己”属性。但是,如果在原型上定义了属性,则没有要删除的“自己”属性,因此删除操作是无操作。该属性在原型上实际上是 (这就是原型继承的工作方式,除非更改了属性,否则该属性实际上不会添加到对象中。)

弄清楚这是一段扭曲的迷宫般的迷宫......也被称为ES5规范,但关键部分(在解码之后)是8.12.7,同时意识到{ {1}}该部分讨论的内部方法将在原型案例中返回GetOwnProperty