How to think about it:
In Javascript and similar languages each object has a prototype which itself is also an object. If you try to access a method or property (since functions are first class in javascript the distinction between method and property is misleading) of an object and if the interpreter can't find on the object itself it will look on the prototype. Since the prototype is also an object it also has its own prototype (the object prototype prototype). So there is this chain of prototypes, one for each level of inheritance that traces all the way up to the base class Object at which point if it still did not find the property you were trying to access the interpreter will throw an undefined property error.
How to implement it:
There are numerous ways to do inheritance, this is the one I use which is not necessarely the best, but is the one easiest to understand:
//A constructor
var A= function() {};
A.prototype.doSomething= function() { };
A.prototype.doSomethingElse= function() { };
//B constructor
var B= function () {
A.apply(this, arguments); //calls A constructor on this instance of B
};
B.prototype= new A(); //this makes B "extend" A. Basically it sets B prototype to be an instance of A.
B.prototype.doSomething= function() {
A.doSomething.apply(this, arguments); //calling "super"
};
B.prototype.doSomethingElse= function() {
A.doSomethingElse.apply(this, arguments); //calling "super"
};
//C constructor
var C= function () {
A.apply(this, arguments);
};
C.prototype= new A();
C.prototype.doSomething= function() {
A.doSomething.apply(this, arguments); //calling "super"
};
C.prototype.doSomethingElse= function() {
A.doSomethingElse.apply(this, arguments); //calling "super"
};
So if say that C does not have the method doSomethingElse and you do something like:
c= new C();
c.doSomethingElse();
It will call A.doSomethingElse method on the c instance.
A little explanation on the .apply function:
Functions in javascript "extend" Object, as such they are object themselves. In fact you can actually do this:
var myFunc= new Function("alert('myFunc');");
myFunc();
Since Functions are objects they also have their own properties and methods. "apply" is one of them.
When you say this:
//A constructor
var A= function() {};
A.prototype.doSomething= function() { };
You are actually creating a function and storing it in A, then you put a method inside A prototype (remember, functions are objects, so they have prototypes). When you do this:
var a= new A(arg1,arg2,arg3...);
You are making an instance of A, the "new" operator is a special kind of operator that basically does this:
a= A.apply(a, [arg1,arg2,arg3,...]);
a.prototype= A.prototype;
Here is an explantion of the Function.apply method:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fapply
And here is an explanation of the "arguments" Array that is passed to it:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments
When you say this:
C.prototype.doSomething= function() {
A.doSomething.apply(this, arguments);
};
Note that A.doSomething in this case is kind of an analogue to a static function in Java, you are not calling the method of an instance of A, but actually the method present on the constructor function A (the method is actually on A.prototype, but since functions are objects the interpreter will look for it on the prototype by itself).
You can do all this because the constructor is a function and functions are objects and objects have prototypes and prototypes are objects and objects can have functions inside them. Crazy huh? But if you stop to think about the prototype chain explanained earlier it's not that hard. Just reread that sentence a couple of times.
Why all this nonsense?
You are probably a little confused right now and I encourage you to look for more examples on the net. But it's easy to say that this is convoluted and overly complex, well it kind of is (in javascript) but it's also very powerful. You can modify the behavior of objects at runtime:
If you execute this little bit of code at any point in runtime
A.prototype.doSomething= function() {
A.doSomethingElse.(apply(this, arguments));
}
you are actually modifying the behavior of all instances of A and any other class that inherits from it (all instances of B and C are also modified). In this case your A.doSomething will now behave exactly like A.doSomethingElse.
Think of Java reflections without all the crazy code.
In fact you can modify the behavior of built-in classes of Javascript like String or Array:
If you run this code somewhere in your program:
String.prototype.alert= function() {
alert(this);
}
You can now do the following:
"text".alert();
And a popup box will appear with "text" inside it. But don't modify built-in classes like that, it's a bad practice.
This is just one of the numerous advantages of using prototype based object orientation. There are many others.
What about private methods?
They don't exist in javascript, but you can make functions that are only visible to another function through closures. If you need to make private methods I encourage you to read about closures.