prototype vs __proto__

Javascript is prototyping language right. Which is "more powerful" than object oriented programming.. since you could "easily" emulate object inheritance with prototypes, but it is hard to emulate prototyping features with classes and objects. Or at least that is the theory.
Class-based object-oriented languages, such as Java and C++, are founded on the concept of two distinct entities: classes and instances.
...
A prototype-based language, such as JavaScript, does not make this distinction: it simply has objects. A prototype-based language has the notion of a prototypical object, an object used as a template from which to get the initial properties for a new object. Any object can specify its own properties, either when you create it or at run time. In addition, any object can be associated as the prototype for another object, allowing the second object to share the first object's properties.

But wrapping your head around prototypes is not as easy as advertised. I had to scratch my head on multiple occasions with "wtf how this works exactly". The prototype chain can be influenced through Object.create(__proto__, properties). Where the __proto__ parameter is the object from which you want to have as immediate parent in the prototype chain.

prototype vs __proto__

The __proto__ property is not standard until ECMAScript 5, and is not supported in some older browsers. But still it is massively supported by most modern browsers to the extend that it will be included in ECMAScript 6. The prototype chain is implemented in Javascript by going through the __proto__ properties until null is reached.

The prototype property is supported on all objects that are functions (i.e. their __proto__ === Function.prototype), i.e. they could act as constructors. When instance of a constructor is created with new, then the __proto__ of the newly created instances is pointed to the object pointed by prototype.

Lets consider this simple example:
var parent = { a : 1 };
// parent inherits from Object.prototype as all objects do. 
// Inheritance is implemented only via the __proto_. This means
// that: parent.__proto__ === Object.prototype
// The prototype property is defined only for Function objects, 
// i.e. parent.prototype === undefined 

var child = Object.create(parent);
// Object.create creates a new object and sets its __proto__
// to the "parent" parameter (the easiest way to prototype), i.e.:
// child.__proto__ == parent
// Since child is normal object, and not Function object, the
// child.prototype === undefined

child.b = 2;

the layout of the objects is as follows:
All squares are separate Javascript objects. The links show the value from a property to an object.
The Object is function constructor. Object.prototype object is the root of almost all prototype chains.
Object.Prototype.__proto__ is null to terminate the prototype chain.
Properties are searched going through the __proto__ chain until null is reached.
With the example above which one will be true:
child.__proto__ === parent
parent.__proto__ === Object.prototype.__proto__
Object.prototype.__proto__ === null

Now, lets consider examples with constructor functions where the prototype property becomes very important.
function Shape() {
  this.instance_id = "Shape_" + Shape.prototype.getNextId();
}

Since all functions could act as constructors to create new objects - they all have default empty prototype object. The object diagram in this case is (yeah.. a lot of objects, for a single function, i.e. for a single constructor)
The Shape function definition created 2 javascript objects.
The Shape object that contains the actual function that inherits (via __proto__) from the Function.prototype object.
The empty Shape.prototype object that is automatically created for all functions.
By default it is empty and like all other objects, unless specified explicitly, inherits (via __proto__)  from Object.prototype.

This are all valid walk throughs the various prototype chains:
Shape.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
Shape.prototype.__proto__.__proto__ === null

Shape.__proto__ === Function.prototype
Shape.__proto__.__proto__ === Object.prototype

Now looking at the maze of prototype and __proto__ links, which of this are true:
Shape.__proto__ === Function.prototype
Shape.prototype === Function.prototype
Shape.prototype.__proto__ === Function.prototype.__proto__

And finally the complete picture when we add some methods to the prototype and the instance:
function Shape() {
  this.instance_id = "Shape_" + Shape.prototype.getNextId();
}

Shape.prototype.id = 0;
Shape.prototype.getNextId = function() { 
    return this.id++;
}
Shape.prototype.toString = function() {
    console.log("This is: "+this.instance_id );
}

// Crate new objects of type Shape
var sh1 = new Shape();
var sh1 = new Shape();


The object diagram in this case will look like:
The sh1 and sh2 objects gets its __proto__ set to the Shape.prototype!
Thus they get access to the id, getNextId() and toString().

Thus if you have read carefully through the confusing labyrinth of links between objects, the following are the conclusions:

  • Method and properties are inherited only through the __proto__ chain !
  • Only the functions have prototype object
  • When creating new object, i.e.: var = new then .__proto__ is set to .prototype. (where  and  are any javacscript function and variable)
  • Setting methods and properties to .prototype will be accessible in via the __proto__ links

Comments

Popular posts from this blog

Data types: Backend DB architecture

Node.js: Optimisations on parsing large JSON file

Back to teaching