Although I have some working experience with jQuery and JavaScript I still find it difficult to understand prototypal inheritance. Hence I have started reading Stoyan Stefanov's book entitled "Object Oriented JavaScript". However I ran into problems while solving the following exercises from the book:
- Create an object called
shape
that has atype
property and agetType
method. - Define a
Triangle
constructor function whose prototype is shape. Objects created withTriangle
should have three own properties:a
,b
andc
representing the sides of a triangle. - Add a new method to the prototype called
getPerimeter
.
Test your implementation with this code:
var t = new Triangle(1, 2, 3);
t.constructor; // Triangle(a, b, c)
shape.isPrototypeOf(t); // true
t.getPerimeter(); // 6
t.getType(); // "triangle"
I have tried to solve this problem with the following code:
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a, b, c) {
}
Triangle.prototype = shape;
However it does not seem to work as expected. How would you solve this problem? Please explain it in detail. I would really like to understand prototypal inheritance.
Although I have some working experience with jQuery and JavaScript I still find it difficult to understand prototypal inheritance. Hence I have started reading Stoyan Stefanov's book entitled "Object Oriented JavaScript". However I ran into problems while solving the following exercises from the book:
- Create an object called
shape
that has atype
property and agetType
method. - Define a
Triangle
constructor function whose prototype is shape. Objects created withTriangle
should have three own properties:a
,b
andc
representing the sides of a triangle. - Add a new method to the prototype called
getPerimeter
.
Test your implementation with this code:
var t = new Triangle(1, 2, 3);
t.constructor; // Triangle(a, b, c)
shape.isPrototypeOf(t); // true
t.getPerimeter(); // 6
t.getType(); // "triangle"
I have tried to solve this problem with the following code:
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a, b, c) {
}
Triangle.prototype = shape;
However it does not seem to work as expected. How would you solve this problem? Please explain it in detail. I would really like to understand prototypal inheritance.
Share Improve this question edited Aug 28, 2013 at 18:38 Aadit M Shah 74.3k31 gold badges175 silver badges307 bronze badges asked Aug 28, 2013 at 17:38 viktorviktor 1,0481 gold badge12 silver badges27 bronze badges 2- Why are there a bunch of � in your code? – Paul Commented Aug 28, 2013 at 17:41
- I copy pasted that directly from the pdf – viktor Commented Aug 28, 2013 at 17:44
5 Answers
Reset to default 3You don't do anything with the params passed to the constructor function, probably assuming that they are just assigned to the newly-created object. The problem is, they aren't.
You should write something like this...
var shape = {
type: '',
getType: function() { return this.type; }
};
function Triangle(a, b, c) {
this.type = 'triangle';
this.a = a;
this.b = b;
this.c = c;
}
Triangle.prototype = shape;
Triangle.prototype.getPerimeter = function() {
return this.a + this.b + this.c;
};
Triangle.prototype.constructor = Triangle;
The point (why constructor
is defined for prototype
) is very simple: each Triangle
object should know about its constructor function, but this property will be the same for each instance of Triangle
. That's why it's placed it on Triangle.prototype
instead.
Something like this will work:
function Shape() {
this.type = "shape";
this.getType = function(){
return this.type;
}
}
function Triangle(a,b,c){
this.type="triangle";
this.a =a;
this.b = b;
this.c = c;
}
var shape = new Shape(); //follow the requirements a bit more literally :)
Triangle.prototype = shape;
Triangle.prototype.getPerimeter = function() {
return this.a + this.b + this.c;
}
jsfiddle example: http://jsfiddle/TbR6q/1
Tangentially, this is an area where coffeescript is very nice and allows you to be much more clear/concise. This is the equivalent in Coffeescript.
class Shape
constructor: ->
@type = "shape"
getType : -> @type
class Triangle extends Shape
constructor: (@a,@b,@c) ->
@type="triangle"
getPerimeter: () -> @a + @b + @c
http://jsfiddle/qGtmX/
You're on the right track. Your code is correct. You only need to add a few more lines of code:
shape = {
type : "",
getType: function () {
return this.type;
}
};
function Triangle(a, b, c) {
this.type = "triangle";
this.a = a;
this.b = b;
this.c = c;
}
Triangle.prototype = shape;
shape.getPerimeter = function () {
return this.a + this.b + this.c;
};
To understand what's happening I suggest you read the following answers:
- Object Inheritance in JavaScript
- What are the downsides of defining functions on prototype this way?
- JavaScript inheritance and the constructor property
For the sake of learning I would make it like this
function Shape(){
this.type = 'Shape';
this.getType = function()
{
return this.type;
}
}
var shape = new Shape();
function Triangle(a, b ,c)
{
this.type = 'triangle';
this.arguments = arguments;
}
Triangle.prototype = shape;
var triangle = new Triangle(1, 2, 3);
triangle.getType();
Triangle.prototype.getParimeter = function()
{
var perimeter = 0;
for(i = 0; i < this.arguments.length; i++){
perimeter = perimeter + this.arguments[i];
}
return perimeter;
}
console.log(triangle.getParimeter());
This is one solution (explanations on ments):
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a,b,c){
//This three variables are defined inside a closure, so in this case
//only the getPermiter function can access them
var A = a, B = b, C = c;
//The new Triangle object is crafted in the lines below as usual
this.type = "triangle";
this.getPerimeter = function(){
return A + B + C;
}
}
//Here we set the triangle prototype to point the shape object.
//So every time we call the Triangle function with the "new" operator
//the __proto__ internal property of the newly created object will be
//the shape object.
Triangle.prototype = Object.create(shape);
//The problem is that the shape object doesn't have a constructor property,
//so the shape constructor is shape.__proto__.constructor, which is the
//Object function.
//All this means that when we create a new object with the Triangle function the
//constructor property will be the Object function (shape.__proto__.constructor).
//To avoid this we must manually set the constructor to be Triangle.
Triangle.prototype.constructor = Triangle;
var t = new Triangle(1, 2, 3);
console.log(t.constructor === Triangle);
console.log(shape.isPrototypeOf(t) === true);
console.log(t.getPerimeter() === 6);
console.log(t.getType() === "triangle");