defineProperty(__proto__, "shenanigans")

# Andrea Giammarchi (12 years ago)

just because I wanted to test which version/engine of V8 or other browsers behaves like that ... most recent, but it hasn't been like this before and I believe before was correct, now it's just confusing. Here many browsers under test: browsershots.org/http://www.3site.eu/dp.html

green means instances have no problems defining properties, red means these have problems with inherited non writable properties. This looks like a with(instance) property = value problem to me, where the property is retrieved through the proto chain rather than assigned to the instance ... unexpected, IMHO

# Brandon Benvie (12 years ago)

The correct behavior is what you observed. If a property is non-writable on a prototype then CanPut (and the refactored SetP) then writing should fail. defineProperty uses DefineOwnProperty which explicitly only operates on the object itself and thus doesn't care about the prototype.

# Brandon Benvie (12 years ago)

Clarification: if an object has no own property, then it defers to the writability from the prototype chain. If it has an own property then it never checks the prototype chain.

# Andrea Giammarchi (12 years ago)

so this mean that freezing a Contructor.prototype to enforce/ensure nobody can change runtime that prototype will result in unusable code as we know, right? Or we should never pre define properties that should be changed runtime? Second one works and stink at the same time.

I preferred the old V8 behavior ... if I freeze a proto the object should not pass through that proto when a property is set unless the proto has a setter ... but this is another story I guess.

Anyway, thanks for explaining this which is gold for a blog post.

br

# Axel Rauschmayer (12 years ago)

This has been discussed a while back: it is similar to how a getter-only accessor works.

[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer axel at rauschma.de Home: rauschma.de Blog: 2ality.com

# Andrea Giammarchi (12 years ago)

I understand the getter/setter logic, I don't get it when it comes to value. Prototype could be used to pre-define shapes too where all properties are described upfront but those with just a value cannot be reused which is a limit if we think about securing prototypes.

Too bad I have missed that discussion

br

# Brandon Benvie (12 years ago)

I recall now that there's actually a strawman about this. strawman:fixing_override_mistake

# Andrea Giammarchi (12 years ago)

so it's not just me ... let's see if I can contribute a bit here with my thoughts ( I think I cannot edit that page )

==== Why it's bad for efficiency ====

Frozen objects can be considered similar to C structs and optimized by ES engines as such. Being prototypal inheritance based on objects, sharing a well defined and frozen shape in the proto level could only brings advantages in therms of performances.

==== Why it's inconvenient ====

Defaults can be defined through proto properties. Once we have a prototype that we would like to ensure/grant as it is and with those defaults, there's no mechanism in current ES specs able to do this. A classic {name:"", age:0} human like prototype could be reused to Object.create(human) related objects where all of them will surely start aging from zero and will have a name as soon as created. All simple mechanism to interact with this instance and its inherited properties will be broken. <code javascript> var human = Object.freeze({name: "", age: 0}); var me = Object.create(human);

// unable to have a name me.name = "Andrea";

// after a year, unable to age me.age++;

[me.name, me.age]; // "", 0 </code>

==== Why it's bad for security ====

There is no way to use in a meaningful way frozen objects when it comes to security and inheritance. Properties with values will make normal objects interaction hard. We don't want to end up with similar hacks to be able to define properties: <code javascript> function setIfPossible(obj, key, value) { var descriptor = Object.getOwnPropertyDescriptor( obj, key ); var set = descriptor.hasOwnProperty("value"); if (set) { Object.defineProperty(obj, key, { enumerable: descriptor.enumerable, writable: true, configurable: true, value: value }); } return set; }

if (!setIfPossible(me, "age", me.age + 1)) { throw "I am Dorian Gray"; } </code>

Accordingly, in order to avoid these problems developers will not use Object.freeze to ensure prototype defaults or, if used, the feeling that properties are not writable and so defaults are safe when simply passing through Object.defineProperty() will make the overwrite possible. As summary, this is a security limit and problem rather than an improvement over most common prototypal use cases.

==== How bad would fixing it be for legacy compatibility? ====

AFAIK there is no legacy based on this assumption. First of all because 90% of libraries are using ES3 code, secondly because nobody would like to have on purpose this behavior which brings nothing. If a constructor should ensure immutable properties, inherited included, it will freeze the instance before returning it by itself. Also the inconsistency is that assigning a property pass through the prozen proto but adding properties not defined in the not extendible proto does not prevent any operation.

How should it be, in my opinion:

if defineProperty is allowed, obj.property = value should be allowed too if the proto.property descriptor contains the value field.

br