Behavior reuse is one of the key aspects of Object Oriented
programming. Many mainstream Object Oriented languages, achieves
behavior reuse by using class based inheritance. In class based inheritance, a class defines how objects stemming from it should behave.
However, not all languages use class based inheritance to achieve
behavior reuse. The best possible example is JavaScript. It doesn�t have
a concept of classes. Some people often confused about JavaScript�s
object oriented capabilities due to this fact. But in reality,
JavaScript is a more expressive and flexible Object Oriented language
compared to some of the mainstream languages.
If JavaScript doesn�t have class based inheritance, how does it reuse the behavior? For that it follows the technique called Prototypal Inheritance.
In prototypal inheritance, an object is used to define the behavior
of another object. Let�s try to understand this with a simple example:
var father = {
first_name: "James",
last_name: "Potter",
hair_color: "black",
is_good_at_quidditch: true,
name: function(){
return this.first_name + " " + this.last_name
}
}
var son = {
first_name: "Harry"
}
son.__proto__ = father;
father.name()
>> James Potter
son.name()
>> Harry Potter
son.hair_color
>> black
son.is_good_at_quidditch
>> true
Here the �father� object acts as the prototype for �son�. Hence, �son� inherits all properties defined for �father� (Note the __proto__ property of �son� object was explicitly overridden to set �father� as the prototype).
Even though it was used as a prototype, �father� object can be still
manipulated as a regular object. This is the main difference of a
prototype from a class.
Object Hierarchy
The process of object responding to a property call in JavaScript is
fairly straight-forward. It will first check whether it defines the
property on its own; if not it will delegate the property call to its
prototype object. This chain will continue to the top of object
hierarchy until the property is found.
Talking about the object hierarchy, all objects in JavaScript are
descended from generic Object. The generic Object prototype is the
default prototype set on all objects at the instantiation, unless a
custom prototype object is defined.
So any given inheritance hierarchy in JavaScript is chain of objects with the generic Object prototype at the root.
Creating New Objects
Though JavaScript doesn�t have classes, you can define a constructor function and call it with the new
keyword to instantiate a new object. As I mentioned before, when the
new object is created it uses the generic Object prototype as its
prototype.
Let�s take an example of creating basic shape objects. The constructor takes the number of sides and vertices as the arguments.
var Shape = function(sides, vertices){
this.sides = sides;
this.vertices = vertices;
}
var triangle = new Shape(3, 3);
What if we want to create different types of triangles? Yes, we can
use our basic shape object as the prototype for all our triangle
objects.
var Triangle = function(angles, side_lengths){
this.angles = angles || [60, 60, 60];
this.side_lengths = side_lengths || [5, 5, 5];
}
Triangle.prototype = new Shape(3, 3);
var isosceles_triangle = new Triangle([70, 70, 40], [5, 5, 10]);
var scalene_triangle = new Triangle([70, 60, 50], [5, 10, 13]);
isosceles_triangle.sides
>> 3
isoceles_triangle.vertices
>> 3
scalene_triangle.sides
>> 3
scalene_triangle.vertices
>> 3
Basically, when you call a constructor function with the new keyword; it will set the __proto__ property of the newly created object to the object defined in prototype property of the constructor function.
Modifying Prototype Object at Runtime
All Objects in JavaScript can be modified during the runtime. Since
prototype objects are also regular objects, we can modify them too.
However, when you modify a prototype object its changes are reflected to
all its descended objects too.
Triangle.prototype.area = function(base, height){
return(1/2 * base * height);
}
isosceles_triangle.area(10, 4);
>> 20
What�s most interesting is we can use this way to extend the built-in
objects in JavaScript. For example, you can extend String object�s
prototype to add a capitalize method.
String.prototype.capitalize = function(){
return this.charAt(0).toUpperCase() + this.slice(1);
};
"john".capitalize();
>> John
Further Reading
If you like to learn more about JavaScript�s object model and
prototypal inheritance, you would find following articles/posts useful.
|