Search code examples
javascriptprototypeprototypal-inheritance

Mdn Docs __proto__ vs __proto__ Accessor


In mdn's doc's for the prototype chain, it states

All objects inherit the Object.prototype.__proto__ setter, which can be used to set the [[Prototype]] of an existing object (if the __proto__ key is not overridden on the object).

It then goes on to say that

Object.prototype.__proto__ accessors are non-standard and deprecated. You should almost always use Object.setPrototypeOf instead.

Along with this example:

const obj = {};
// DON'T USE THIS: for example only.
obj.__proto__ = { barProp: 'bar val' };
obj.__proto__.__proto__ = { fooProp: 'foo val' };
console.log(obj.fooProp);
console.log(obj.barProp);

The part that is confusing is they start the docs out with this example:

const o = {
  a: 1,
  b: 2,
  // __proto__ sets the [[Prototype]]. It's specified here
  // as another object literal.
  __proto__: {
    b: 3,
    c: 4,
  },
};

Stating that,

{ __proto__: ... } syntax is different from the obj.__proto__ accessor: the former is standard and not deprecated.

How is { __proto__: ...} different from obj.__proto__? Both are properties of an object, and I'm not quite clear on what the difference is here.


Solution

  • It's just the way the syntax was designed. (See here and here.) Assigning to the __proto__ of an existing object is deprecated, but specifying a __proto__ at the point when the object is created is not.

    One reason for why an object literal can have it but doing so with an already existing object is not recommended is because, as MDN says on the subject of changing an object's prototype:

    Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, currently a very slow operation in every browser and JavaScript engine. In addition, the effects of altering inheritance are subtle and far-flung, and are not limited to the time spent in the Object.setPrototypeOf(...) statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. You can read more in JavaScript engine fundamentals: optimizing prototypes.

    Because this feature is a part of the language, it is still the burden on engine developers to implement that feature performantly (ideally). Until engine developers address this issue, if you are concerned about performance, you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().

    In well-designed code, there should not be a need to dynamically change the internal prototype of an already existing object. In contrast, it's completely normal to want to specify an internal prototype when creating an object initially.

    (Setting a new internal prototype of an object can be done with setPrototypeOf, which is not recommended, and by assigning to the object's __proto__, which is not only not recommended, but deprecated as well)