Formalizing the __proto__
Property
Even before ECMAScript 5 was finished, several JavaScript engines already implemented a custom property called __proto__
that could be used to both get and set the [[Prototype]]
property. Effectively, __proto__
was an early precursor to both the Object.getPrototypeOf()
and Object.setPrototypeOf()
methods. Expecting all JavaScript engines to remove this property is unrealistic (there were popular JavaScript libraries making use of __proto__
), so ECMAScript 6 also formalized the __proto__
behavior. But the formalization appears in Appendix B of ECMA-262 along with this warning:
These features are not considered part of the core ECMAScript language. Programmers should not use or assume the existence of these features and behaviours when writing new ECMAScript code. ECMAScript implementations are discouraged from implementing these features unless the implementation is part of a web browser or is required to run the same legacy ECMAScript code that web browsers encounter.
The ECMAScript specification recommends using Object.getPrototypeOf()
and Object.setPrototypeOf()
instead because __proto__
has the following characteristics:
- You can only specify
__proto__
once in an object literal. If you specify two__proto__
properties, then an error is thrown. This is the only object literal property with that restriction. - The computed form
["__proto__"]
acts like a regular property and doesn’t set or return the current object’s prototype. All rules related to object literal properties apply in this form, as opposed to the non-computed form, which has exceptions.
While you should avoid using the __proto__
property, the way the specification defined it is interesting. In ECMAScript 6 engines, Object.prototype.__proto__
is defined as an accessor property whose get
method calls Object.getPrototypeOf()
and whose set
method calls the Object.setPrototypeOf()
method. This leaves no real difference between using __proto__
and Object.getPrototypeOf()
/Object.setPrototypeOf()
, except that __proto__
allows you to set the prototype of an object literal directly. Here’s how that works:
let person = {
getGreeting() {
return "Hello";
}
};
let dog = {
getGreeting() {
return "Woof";
}
};
// prototype is person
let friend = {
__proto__: person
};
console.log(friend.getGreeting()); // "Hello"
console.log(Object.getPrototypeOf(friend) === person); // true
console.log(friend.__proto__ === person); // true
// set prototype to dog
friend.__proto__ = dog;
console.log(friend.getGreeting()); // "Woof"
console.log(friend.__proto__ === dog); // true
console.log(Object.getPrototypeOf(friend) === dog); // true
Instead of calling Object.create()
to make the friend
object, this example creates a standard object literal that assigns a value to the __proto__
property. When creating an object with the Object.create()
method, on the other hand, you’d have to specify full property descriptors for any additional object properties.