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:

  1. 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.
  2. 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:

  1. let person = {
  2. getGreeting() {
  3. return "Hello";
  4. }
  5. };
  6. let dog = {
  7. getGreeting() {
  8. return "Woof";
  9. }
  10. };
  11. // prototype is person
  12. let friend = {
  13. __proto__: person
  14. };
  15. console.log(friend.getGreeting()); // "Hello"
  16. console.log(Object.getPrototypeOf(friend) === person); // true
  17. console.log(friend.__proto__ === person); // true
  18. // set prototype to dog
  19. friend.__proto__ = dog;
  20. console.log(friend.getGreeting()); // "Woof"
  21. console.log(friend.__proto__ === dog); // true
  22. 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.