In JavaScript, the prototype
object is attached to every object on the page, either already existing or created from scratch. This object handles all the features related to objects, classes and, more broadly, inheritance. Since JavaScript is prototypical in its nature, it's almost impossible to work in a OO way without dealing with it. As you may have guessed, in JavaScript functions are actually first-class objects, so it's natural that every function that works as a class has its own prototype
object. Strictly speaking, this object can also be considered as a property of every object, although not in the narrowest sense of the term.
The best way to understand this is simply one: testing! So let's test something by starting with a base class like this:
function Class() { this.property = 'Property'; } alert(Class.prototype); // [object Object] var myClass = new Class();
Now let's see what is our default setup:
alert(myClass.constructor); // function Class() {...} alert(myClass.prototype); // undefined
As you can see, the constructor
property of our class simply points to our function, while the prototype
object of the instance is undefined
. But we can actually use this property to extend our base class with a subclass, like so:
function SubClass() { this.say = function() { alert(this.property); } } Class.prototype = new SubClass(); var myClass = new Class(); myClass.say(); // 'Property'
Making the prototype
object of our base class pointing to a new instance of our subclass, we actually extend our base class with the new method. But our prototype
object (that of the instance) is still undefined
:
alert(myClass.prototype); // undefined
The fact is that now prototype
is not still associated with an object. Let's see another aspect:
function ClassB () { this.prop = 'Second property'; } ClassB.prototype = { constructor: ClassB, method: function() { alert(this.prop); } } var myClassB = new ClassB(); alert(myClassB.constructor); // function ClassB() {...} alert(myClassB.prototype); // undefined alert(myClassB.constructor.prototype); // [object Object] myClassB.method(); // 'Second property'
In this case, we've associated the prototype
object with an object literal. Inside this object, we've properly set the constructor
property to make it point to our class constructor. As you can see, the prototype
object of the constructor is now associated with an object. Let's do a simple test:
ClassB.prototype.method.call(myClassB); // 'Second property'
This works because we're using the prototype
object of the constructor, not of the instance. The instance is here used only to get the desired value by using call()
on the newly created instance.