2

我在对象和适当的单元测试上创建了一个只读属性。

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

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

//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/来演示这个问题。我用 chrome 和 firefox 在 Mac 上确认了相同的行为。

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

4

2 回答 2

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"

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

于 2013-01-24T07:34:47.993 回答
1

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

弄清楚这是一个曲折的通道迷宫,所有类似的......也称为 ES5 规范,但关键部分(在解码后)是8.12.7,再加上意识到该GetOwnProperty部分中讨论的内部方法将undefined在原型案例中返回。

于 2013-01-24T07:33:33.093 回答