There are a ton of examples out there of how to Prototype with Javascript. The examples I have seen appear too complex, verbose or just plain wrong. I started OO in Java and found the switch to Javascript incredibly difficult because of some bad descriptions of what was a Prototype was actually used for.
ConstructorsPrototypes are NOT blueprints of an object. They are just links to objects you want to inherit member variables from. But it is not any use knowing what a Prototype is, unless you first know what a Constructor is. So lets jump right in and define a Constructor.
// A constructor
God = function God(){
this.myName = 'YHWH';
this.thinks = true;
}
A Constructor is simply a function. The Constructor function has member variables. In this case the member variables are 'myName' and 'thinks'. Using 'new' Now we are able to make copies of Gods.
// Create some Gods
Father = new God;
Son = new God;
Spirit = new God;
Thus we have created 3 new Gods. Each of these Gods has their own name and their own thoughts. Important: they have NOT 'inherited' the member variables from the God constructor. The member varibles are new, as each new instance of God is... 'new'. IE: God does not inherit anything from God, when God is at the top of the chain.
PrototypesOnce you understand that a Constructor is just a function used to create a 'new' instance and set new member variables within that instance... you will find it easy to comprehend what a Prototype is.
Prototypes are not 'created', that's the Constructor's job. Prototypes are linked. Lets say that God wanted to create Man. First God would need a constructor function by which to make the man. So lets code one...
// Define Man's Constructor
Man = function Man( name ){
this.myName = name;
this.dna = 'ACGT';
}
Now you can create a new Man like this...
Adam = new Man( 'Adam' );
Here we set the name-space 'Adam' to store a new instance of Man. When we invoke 'new Man', we want to pass Adam his name, so: 'new Man( 'adam' )'. Thus the Man construtor is run and Adam's member variables are set. But in this case... we have created a dead man (Adam can not think).
God can think but Adam can't. Wouldn't it be nice if Adam could inherit his thinking ability from his Creator? It would, and he can. This is where Prototype is used. Let's append the Man object...
// Define Man's Constructor
Man = function Man( name ){
this.myName = name;
this.dna = 'ACGT';
}
// Define Man's Prototype
Man.prototype = new God;
Ahha! Now when ever a new Man is created, the new man gains the ability to think from his creator. Pointing Man's prototype to 'new God' creates a link that copies the member variables from the God constructor to the new instance of Man.
Prototypes are LinksTaking things to their logical conclusion: now that Man can think, he can realize that he is alone and needs a new Woman. Now we define the constructor function for Woman.
Woman = function Woman( name ){
this.myName = name;
this.womb = true;
}
Woman.prototype = new Man;
Notice that Woman's prototype is Man. This means that any new Woman will inherit the Man constructor's member variables. Thus the Woman inherits DNA from the Man. Woman additionally gains a member variable called 'womb', which Man and God do not have.
So here is where the beauty really comes in: Woman can think, even though Man has no thinking ability in his constructor. This is because prototypes are links. And what do links form? Chains!
As you chained Woman to Man, every time you create a new instance of Woman, she inherits her member variables from new Man, who inherits his member variables from new God. Thus we have a chain of inheritance, and anything you set at the top level will filter down to the bottom unless you explicitly stop or redirect the flow of information.
All the CodeLets put it all together and see what we get.
// God constructor
God = function God(){
this.myName = 'YHWH';
this.thinks = true;
}
// Man constructor
Man = function Man( name ){
this.myName = name;
this.dna = 'ACGT';
}
// Man's Prototype is God's constructor
Man.prototype = new God;
//Woman constructor
Woman = function Woman( name ){
this.womb = true;
}
// Woman's Prototype is Mans's constructor & Man's prototype
Woman.prototype = new Man;
// Run the Man constructor against the new Woman object ( so Woman gets a name )
Woman.prototype.constructor = Man;
// A method to see inside the object
function inspect( being ){
var arr = {};
for( var i in being ){
arr[ i ] = being[ i ];
}
console.log( being.name || being.myName, arr );
}
/* Make an Adam & Eve from Woman & Man constructors...
...inheriting members from their prototypes links */
Adam = new Man( 'Adam' );
( Eve = new Woman ).constructor( 'Eve' );
// Console log for clarity
inspect( God );
inspect( Man );
inspect( Woman );
inspect( Adam );
inspect( Eve );
// constructor properties get added first
// then prototyped properties get inherited second
Results:
God Object prototype=Object
Man Object prototype=Object
Woman Object prototype=Object
Adam Object myName=Adam dna=ACGT thinks=true
Eve Object myName=Eve womb=true dna=ACGT thinks=true
Conclusion:Pretty much everyone knows the account of Genesis, so we all know the fundamental differences between God, Man and Woman. Hopefully this has helped make Prototypes easier to understand for someone out there.
Prototypes are really very simple, but the terminology can be pretty confusing when you look at all the examples out there, especially if you are just beginning to learn Object Oriented patterns. I started learning OO in Java which was much easier to understand than JS. But now that I have been using Prototypal behavior in Javascript for a while, I have to say... I prefer it.