Inheritance - prototype chaining

Description

We can use use the concept of prototypes to inherit properties and methods between two reference types.

Example

Implementing prototype chaining involves the following code pattern:


function Shape(){//from  ww  w.j a  v a  2  s .  co  m
   this.isDrawable = true;
}
Shape.prototype.getDrawable = function(){
   return this.isDrawable;
};

function Rectangle(){
   this.hasFourEdges = false;
}

//inherit from Shape
Rectangle.prototype = new Shape();

Rectangle.prototype.getFourEdges = function (){
   return this.hasFourEdges;
};

var instance = new Rectangle();
console.log(instance.getDrawable());   //true

This code defines two types: Shape and Rectangle.

Rectangle inherits from Shape by creating a new instance of Shape and assigning it to Rectangle.prototype.

This overwrites the original prototype and replaces it with a new object, which means that all properties and methods that typically exist on an instance of Shape now also exist on Rectangle.prototype.

After the inheritance takes place, a method is assigned to Rectangle.prototype, adding a new method on top of what was inherited from Shape.

instance points to Rectangle.prototype, and Rectangle.prototype points to Shape.prototype.

The code above generates the following result.

Prototype and Instance Relationships


function Shape(){//from w  w w .  ja  va 2 s .co  m
   this.isDrawable = true;
}
Shape.prototype.getDrawable = function(){
   return this.isDrawable;
};

function Rectangle(){
   this.hasFourEdges = false;
}

//inherit from Shape
Rectangle.prototype = new Shape();

Rectangle.prototype.getFourEdges = function (){
   return this.hasFourEdges;
};

var instance = new Rectangle();

console.log(instance instanceof Object);      //true
console.log(instance instanceof Shape);   //true
console.log(instance instanceof Rectangle);     //true

The code above generates the following result.

isPrototypeOf

We can also use the isPrototypeOf() method.

Each prototype in the chain has access to this method, which returns true for an instance in the chain, as in this example:


function Shape(){//  w ww  . j  av a  2 s  .  c o  m
   this.isDrawable = true;
}
Shape.prototype.getDrawable = function(){
   return this.isDrawable;
};

function Rectangle(){
   this.hasFourEdges = false;
}

//inherit from Shape
Rectangle.prototype = new Shape();

Rectangle.prototype.getFourEdges = function (){
   return this.hasFourEdges;
};

var instance = new Rectangle();

console.log(Object.prototype.isPrototypeOf(instance));    //true
console.log(Shape.prototype.isPrototypeOf(instance)); //true
console.log(Rectangle.prototype.isPrototypeOf(instance));   //true

The code above generates the following result.

Methods

Often a Rectangle will need to either override a Shape method or introduce new methods that don't exist on the Shape.

To accomplish this, the methods must be added to the prototype after the prototype has been assigned. Consider this example:


function Shape(){/*from w w  w.ja  va  2  s  . c  o m*/
    this.isDrawable = true;
}
Shape.prototype.getDrawable = function(){
    return this.isDrawable;
};
function Rectangle(){
    this.hasFourEdges = false;
}
//inherit from Shape
Rectangle.prototype = new Shape();

//new method
Rectangle.prototype.getFourEdges = function (){
    return this.hasFourEdges;
};
//override existing method
Rectangle.prototype.getDrawable = function (){
    return false;
};
var instance = new Rectangle();
console.log(instance.getDrawable());   //false

The code above generates the following result.

Problems with Prototype Chaining

prototype properties containing reference values are shared with all instances; this is why properties are typically defined within the constructor instead of on the prototype.

When implementing inheritance using prototypes, the prototype actually becomes an instance of another type. What once were instance properties become prototype properties.


function Shape(){//ww  w.  ja v  a  2s  . co  m
    this.colors = ["red", "blue", "green"];
}
function Rectangle(){
}

//inherit from Shape
Rectangle.prototype = new Shape();

var instance1 = new Rectangle();
instance1.colors.push("black");
console.log(instance1.colors);    //"red,blue,green,black"

var instance2 = new Rectangle();
console.log(instance2.colors);    //"red,blue,green,black"

A second issue with prototype chaining is that you cannot pass arguments into the Shape constructor when the Rectangle instance is being created.

The code above generates the following result.





















Home »
  Javascript »
    Javascript Introduction »




Script Element
Syntax
Data Type
Operator
Statement
Array
Primitive Wrapper Types
Function
Object-Oriented
Date
DOM
JSON
Regular Expressions