How does __proto__ differ from constructor.prototype?

Viewed 55850
function Gadget(name, color)
{
   this.name = name;
   this.color = color;
}

Gadget.prototype.rating = 3

var newtoy = new Gadget("webcam", "black")

newtoy.constructor.prototype.constructor.prototype.constructor.prototype 

It always returns the object with rating = 3.

But if I do the following:

newtoy.__proto__.__proto__.__proto__

The chain ends up returning null.

Also in Internet Explorer how would I check the null if there is not a __proto__ property?

8 Answers

constructor is a pre-defined [[DontEnum]] property of the object pointed to by the prototype property of a function object and will initially point to the function object itself.

__proto__ is equivalent to the internal [[Prototype]] property of an object, ie its actual prototype.

When you create an object with the new operator, its internal [[Prototype]] property will be set to the object pointed to by the constructor function's prototype property.

This means that .constructor will evaluate to .__proto__.constructor, ie the constructor function used to create the object, and as we have learned, the protoype property of this function was used to set the object's [[Prototype]].

It follows that .constructor.prototype.constructor is identical to .constructor (as long as these properties haven't been overwritten); see here for a more detailed explanation.

If __proto__ is available, you can walk the actual prototype chain of the object. There's no way to do this in plain ECMAScript3 because JavaScript wasn't designed for deep inheritance hierarchies.

If all those figures were overwhelming, let's take a look what the properties mean.

STH.prototype

When creating a new function, there is an empty object being created in parallel and linked to the function with [[Prototype]] chain. To access this object, we use prototype property of the function.

function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}

Bear in mind that prototype property is only available for functions.

STH.constructor

The prototype object mentioned above has no properties except for one - constructor. This property represents a function that created the prototype object.

var toy = new Gadget();

When creating Gadget function, we created an object like {constructor: Gadget} as well - that is nothing like Gadget.prototype. As constructor refers to a function that created an object prototype, toy.constructor represents Gadget function. We write toy.constructor.prototype and we are getting {constructor: Gadget} again.

Therefore, there's a vicious circle: you can use toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype and it always will be Gadget.prototype.

toy
.constructor    // Gadget
.prototype    // {constructor: Gadget}
.constructor    // Gadget
.prototype    // {constructor: Gadget}
// ...

STH.__proto__

While prototypeis a property specific for functions, __proto__ is available for all objects as it lays in Object.prototype. It refers to prototype of a function that can create an object.

[].__proto__ === Array.prototype
// true

({}).__proto === Object.prototype
// true

Here, toy.__proto__ is Gadget.prototype. As Gadget.prototype is an object ({}) and objects are created with Object function (see the example above), we get Object.prototype. This is the higher object in JavaScript and its __proto__ can only indicate null.

toy
.__proto__    // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__    // Object.prototype (topmost object in JS)
.__proto__    // null - Object.prototype is the end of any chain

Short answer: __proto__ is a reference to the prototype property of the constructor that created the object.

Objects in JavaScript

A JavaScript object is a built-in type for a collection of zero or more properties. Properties are containers that hold other objects, primitive values, or functions.

Constructors in JavaScript

Functions are regular objects (which implement [[Call]] in ECMA-262 terms) with the additional capability of being callable but play another role in JavaScript: they become constructors (factories for objects) if invoked via the new operator. Constructors are thus a rough analog to classes in other languages.

Every JavaScript function is actually an instance of the Function built-in function object that has a special property named prototype used to implement prototype-based inheritance and shared properties. Every object created by a constructor function has an implicit reference (called the prototype or __proto__) to the value of its constructor prototype.

The constructor prototype is a sort of blueprint for building objects since every object created by the constructor inherits a reference to its prototype.

The prototype chain

An object specifies its prototype via the internal property [[Prototype]] or __proto__. The prototype relationship between two objects is about inheritance: every object can have another object as its prototype. The prototype may be the null value.

The chain of objects connected by the __proto__ property is called the prototype chain. When a reference is made to a property in an object, that reference is to the property encountered in the first object in the prototype chain that contains a property of that name. The prototype chain behaves as if it were a single object.

prototype-inheritance.jpg

Whenever you try to access a property in an object, JavaScript starts the search for it in that object and continues with its prototype, the prototype's prototype and so on until the property is encountered or if __proto__ holds the value null.

This type of inheritance using the prototype chain is often called delegation to avoid confusion with other languages using the class chain.

Almost all objects are instances of Object, because Object.prototype is last in their prototype chain. But Object.prototype is not an instance of Object because Object.prototype.__proto__ holds the value null.

You can also create an object with a null prototype like this:

var dict = Object.create(null);

Such an object is a better map (dictionary) than a literal object, which is why this pattern is sometimes called the dict pattern (dict for dictionary).

Note: literal objects created using {} are instances of Object since ({}).__proto__ is a reference to Object.prototype.

Related