defineProperty(__proto__, "shenanigans")

Andrea Giammarchi andrea.giammarchi at gmail.com
Wed Nov 7 08:58:58 PST 2012


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



On Tue, Nov 6, 2012 at 7:50 PM, Brandon Benvie <brandon at brandonbenvie.com>wrote:

> I recall now that there's actually a strawman about this.
> http://wiki.ecmascript.org/doku.php?id=strawman:fixing_override_mistake
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20121107/73dc265b/attachment.html>


More information about the es-discuss mailing list