Question

I created a read only property on an object and the appropriate unit tests.

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

However, I realized that I should have been putting the readonly property on the prototype instead of each individual instance. I changed my code and then one of my tests failed.

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

It appears that when deleting a read-only property on the prototype, no exception is thrown, but when the property is on the object, an exception is thrown.

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

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

I created http://jsfiddle.net/pdgreen/3BGfM/ to demonstrate the problem. I confirmed the same behavior on Mac with chrome and firefox.

Is this the correct thing to happen? Why if the property is on the object, an exception is thrown, but on the prototype, no exception? This surprises me. Can anyone explain why it is so?

Was it helpful?

Solution

That's the correct behavior you're seeing. The 'delete' keyword only deletes an object's own properties; it can't delete the object's prototype's properties. (And if it did, that would be terrible -- it would mess up any other objects inheriting from that same prototype!)

Try the following:

> 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"

The key to prototypical inheritance is that prototypes are actual objects containing their own properties, and that inheritance is fully live and dynamic. If an object doesn't define a property but an object in its prototype chain does, the child object inherits that value. When its value gets overridden locally, it now defines that property itself. If the child object's property gets deleted, the value from the prototype comes through again.

OTHER TIPS

When the property is defined directly on the object, then the object has an "own" property that can be deleted. However, if the property is defined on the prototype, then there is no "own" property to delete, so the delete operation is a no-op. The property is actually on the prototype, (that is how prototypical inheritance works, the property isn't actually added to the object unless it is changed).

Figuring this out is a twisted maze of passages, all alike... also known as the ES5 spec, but the key section (after decoding your way to it) is 8.12.7, coupled with realizing that the GetOwnProperty internal method discussed in that section will return undefined in the prototype case.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top