__proto__ in Object Literals
Version: ES2015 (officially)
Level: Intermediate
Normally, for access to an object’s prototype, you’d use Object.getPrototypeOf()
and Object.setPrototypeOf()
. But there’s also the deprecated __proto__
accessor property for objects that inherit from the Object type that can also give you the same kind of access. That __proto__
identifier is not only accessible from existing object values but can also be used directly in object literals to set the prototype for the object being created.
let defaults = { color: 'red' };
let styles = {
fontSize: 'large',
__proto__: defaults // sets prototype
};
console.log(styles.color); // red
console.log(Object.getPrototypeOf(styles) === defaults); // true
When used this way, it does not invoke the __proto__
accessor. It’s actually something else entirely (remember, object literal values are defined, not assigned). Instead, there’s a special case made specifically for the handling of this property when used directly within an object literal by name. Instead of becoming a property, the value of __proto__
is removed and used as though the object were created using Object.create(__proto__)
.
This behavior only applies when using a non-computed version of this identifier. If you were to use a computed property, or otherwise dynamically add the property through something like a spread, the prototype would not be set. You have to explicitly include the property in the source code by name. This prevents accidental prototype assignments through dynamic keys.
let defaults = { color: 'red' };
let styles = {
fontSize: 'large',
['__proto__']: defaults // sets property named __proto__
};
console.log(styles.color); // undefined
console.log(Object.getPrototypeOf(styles) === defaults); // false
console.log(styles.__proto__); // {color: "red"}
Though the __proto__
property is in the ECMAScript specification as part of the standard, it’s only specified as a feature for web browsers for legacy reasons. Non-browser clients can decide not to support __proto__
and still be considered standard compliant. As a result, you might not want to rely on using __proto__
, as seen here, or as an accessor property.
More info: