Prototype methods, objects without __proto__



The modern methods are:

These should be used instead of __proto__.

For instance:

let animal = {
  eats: true

// create a new object with animal as a prototype
let rabbit = Object.create(animal);

alert(rabbit.eats); // true
alert(Object.getPrototypeOf(rabbit) === animal); // get the prototype of rabbit



let animal = {
  eats: true

let rabbit = Object.create(animal, {
  jumps: {
    value: true

alert(rabbit.jumps); // true



// fully identical shallow clone of obj


Brief history

If we count all the ways to manage [[Prototype]], there’s a lot! Many ways to do the same!

Why so?

That’s for historical reasons.

  • The "prototype" property of a constructor function works since very ancient times.
  • Later in the year 2012: Object.create appeared in the standard. It allowed to create objects with the given prototype, but did not allow to get/set it. So browsers implemented non-standard __proto__ accessor that allowed to get/set a prototype at any time.
  • Later in the year 2015: Object.setPrototypeOf and Object.getPrototypeOf were added to the standard, to perform the same functionality as __proto__. As __proto__ was de-facto implemented everywhere, it was kind-of deprecated and made its way to the Annex B of the standard, that is optional for non-browser environments.

As of now we have all these ways at our disposal.


Don’t reset [[Prototype]] unless the speed doesn’t matter

Technically, we can get/set [[Prototype]] at any time. But usually we only set it once at the object creation time, and then do not modify: rabbit inherits from animal, and that is not going to change.

And JavaScript engines are highly optimized to that. Changing a prototype “on-the-fly” with Object.setPrototypeOf or obj.__proto__= is a very slow operation, it breaks internal optimizations for object property access operations. So evade it unless you know what you’re doing, or JavaScript speed totally doesn’t matter for you.

“Very plain” objects



Check out the example:

let obj = {};

obj[key] = "some value";


Here if the user types in __proto__, the assignment is ignored!

That shouldn’t surprise us. The __proto__ property is special: it must be either an object or null, a string can not become a prototype.


Here the consequences are not terrible. But in other cases, we may be assigning object values, then the prototype may indeed be changed. As the result, the execution will go wrong in totally unexpected ways.


Unexpected things also may happen when accessing toString property – that’s a function by default, and other built-in properties.

How to evade the problem?

First, we can just switch to using Map, then everything’s fine.

But Object also can serve us well here, because language creators gave a thought to that problem long ago.

The __proto__ is not a property of an object, but an accessor property of Object.prototype:



Now, if we want to use an object as an associative array, we can do it with a little trick:

let obj = Object.create(null);

obj[key] = "some value";




We can call such object “very plain” or “pure dictionary objects”, because they are even simpler than regular plain object {...}.


let obj = Object.create(null);

alert(obj); // Error (no toString)

…But that’s usually fine for associative arrays.


let chineseDictionary = Object.create(null);
chineseDictionary.hello = "你好";
chineseDictionary.bye = "再见";



Modern methods to setup and directly access the prototype are:

The built-in __proto__ getter/setter is unsafe if we’d want to put user-generated keys in to an object. Just because a user may enter “proto” as the key, and there’ll be an error with hopefully easy, but generally unpredictable consequences.




We also made it clear that __proto__ is a getter/setter for [[Prototype]] and resides in Object.prototype, just as other methods.


All methods that return object properties (like Object.keys and others) – return “own” properties. If we want inherited ones, then we can use


importance: 5


Add method dictionary.toString() into it, that should return a comma-delimited list of keys. Your toString should not show up in over the object.

Here’s how it should work:

let dictionary = Object.create(null);

// your code to add dictionary.toString method

// add some data = "Apple";

// only apple and __proto__ are in the loop
for(let key in dictionary) {

// your toString in action
alert(dictionary); // "apple,__proto__"



let dictionary = Object.create(null, {
  toString: { // define toString property
    value() { // the value is a function
      return Object.keys(this).join();
}); = "Apple";
dictionary.__proto__ = "test";

// apple and __proto__ is in the loop
for(let key in dictionary) {

// comma-separated list of properties by toString
alert(dictionary); // "apple,__proto__"


See the the chapter Property flags and descriptors for review.

importance: 5

Let’s create a new rabbit object:

function Rabbit(name) { = name;
Rabbit.prototype.sayHi = function() {

let rabbit = new Rabbit("Rabbit");

These calls do the same thing or not?




function Rabbit(name) { = name;
Rabbit.prototype.sayHi = function() {
  alert( );

let rabbit = new Rabbit("Rabbit");

rabbit.sayHi();                        // Rabbit
Rabbit.prototype.sayHi();              // undefined
Object.getPrototypeOf(rabbit).sayHi(); // undefined
rabbit.__proto__.sayHi();              // undefined
Tutorial map


read this before commenting…