0

I need to print the shape of the object in the constructor Shape(), in which the instances of 'triangle' and 'square' inherit Shape() constructor. I then call a method inside Shape(), called get_type to display the shape type.

function Shape() {
  this.type = '';

  this.get_type = function() {
    console.log(this.constructor)
  }
}

function Triangle(s1, s2, s3) {
  this.side1 = s1;
  this.side2 = s2;
  this.side3 = s3;
}

function Square(s1, s2, s3, s4) {
  this.side1 = s1;
  this.side2 = s2;
  this.side3 = s3;
  this.side4 = s4;
}

var triangle = new Triangle(10, 8, 15);

Triangle.prototype = new Shape();
console.log(Triangle.prototype); //Shows the Shape() function on console.
console.log(triangle.side1, triangle.side2, triangle.side3) //Shows the Triangle constructor works.
console.log(triangle.type); //Undefined

triangle.get_type(); // Get a not a function error.
Rajesh
  • 24,354
  • 5
  • 48
  • 79
H. Lee
  • 67
  • 1
  • 9
  • 1
    Please see [Benefits of using `Object.create` for inheritance](http://stackoverflow.com/a/17393153/218196) . But since you are using Node.js, you really should be using [`class`es](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). `get_type` will only work if you are fixing the `constructor` property. See [Why is it necessary to set the prototype constructor?](http://stackoverflow.com/q/8453887/218196) for that. – Felix Kling Dec 07 '16 at 05:21

3 Answers3

2

You're setting the prototype of the Triangle function after you've already used it to construct your triangle object. Changing Triangle.prototype to refer to a new object will not change the prototype of triangle.

Move the line Triangle.prototype = new Shape() to be above var triangle = new Triangle(10, 8, 15); if you want triangle to inherit methods and properties from Shape.

PMV
  • 2,058
  • 1
  • 10
  • 15
  • That alone won't make the `get_type` function work though. – Felix Kling Dec 07 '16 at 05:24
  • @FelixKling - Yes, without other changes it will return Shape() and not Triangle(). Fixing that would require setting Triangle.prototype.constructor manually. – PMV Dec 07 '16 at 05:44
0

It looks like you have several issues:

  1. Your get_type function should be added to the prototype so as to avoid creating a new method for every Shape instantiated.
  2. new Triangle should not be called before Triangle is made to inherit from Shape (by setting Triangle.prototype = new Shape).
  3. You have to manually set Triangle.prototype.constructor = Triangle. (For the rationale, see this existing answer.)

function Shape() {
    this.type = ''
}

Shape.prototype.get_type = function () {
    return this.constructor
}

function Triangle(s1, s2, s3) {
    this.type = 'triangle'
    this.side1 = s1
    this.side2 = s2
    this.side3 = s3
}

Triangle.prototype = new Shape
Triangle.prototype.constructor = Triangle

function Square(s1, s2, s3, s4) {
    this.type = 'square'
    this.side1 = s1;
    this.side2 = s2;
    this.side3 = s3;
    this.side4 = s4;
}

var triangle = new Triangle(10, 8, 15)

console.log(Triangle.prototype) //=> [Shape]
console.log(triangle.side1, triangle.side2, triangle.side3) //=> 10, 8, 15
console.log(triangle.type); //=> 'triangle'
console.log(triangle.get_type()) //=> [Function Triangle]
gyre
  • 16,369
  • 3
  • 37
  • 47
  • `triangle.get_type()` returns the `Shape` function, not `Triangle`. – Felix Kling Dec 07 '16 at 05:23
  • Just solved that problem. Had to set the `constructor` property of the new prototype manually. – gyre Dec 07 '16 at 05:26
  • how come you put the get_type function outside the Shape() constructor? Does it matter? And also, I am not suppose to have the type property. – H. Lee Dec 07 '16 at 05:34
  • I defined `get_type` outside of the constructor because that ensures only a single function is ever created to act as that method. Your code generated a new function *per object* instantiated, which is unnecessary. You can delete the `type` property without changing the other functionality. – gyre Dec 07 '16 at 05:45
  • `Triangle.prototype = new Shape()).constructor = Triangle` In this part, are you first inheriting the properties of the Shape function/constructor and then making the Shape() function/constructor inherit the properties of the Triangle function/constructor? – H. Lee Dec 07 '16 at 05:46
  • Yeah, that could be better written as two lines. Let me update my answer. – gyre Dec 07 '16 at 05:49
  • Aren't you essentially inheriting the Triangle constructor into the Triangle Constructor? Why would we have to re inherit the Triangle constructor when that what we started off with? Isnt the `Triangle.prototype.constructor = Triangle` making the Triangle constructor have its properties plus the additonal properties of Shape()? – H. Lee Dec 07 '16 at 05:59
  • I understand your confusion; this is a difficult topic and probably not well-suited for the comments section. There is [an existing answer here](https://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor) that might shed some light on that technique. – gyre Dec 07 '16 at 06:10
0

You have the prototype attached after the object has already been initialized. Moving your prototype assignment before you create the triangle object, would give you access to get_type.

However, because the way you are assigning the prototype, you dont get the reference of actual constructor function name.Primary reason for this behaviour is that you are actually creating an instance of Shape object independent of the constructor and referencing that instance as a prototype for Triangle / Square. Shape constructor doesn't get executed when you instantiate Triangle / Square constructors.

To get around this issue, you could use Function.call.

You could use the code snippet as reference.

In the snippet, you could see the Shape constructor is being called on each Triangle / Square object instantiations and now, you could see the constructor reference as Triangle / Square as per the instance.

But this approach has its own drawback, as you could see any methods that are defined on the prototype of Shape aren't available on the Traiangle / Square. To make this work, you need to have your methods in Shape constructor and not use prototype, if you are ok with it.

function Shape() {
  this.type = 'emptyString';

  this.get_type = function() {
    console.log(this.constructor.name)
  }
}
Shape.prototype.getSomeValue = function() {
  console.log("1234");
}

function Triangle(s1, s2, s3) {
  Shape.call(this);
  this.side1 = s1;
  this.side2 = s2;
  this.side3 = s3;
}

function Square(s1, s2, s3, s4) {
  Shape.call(this);
  this.side1 = s1;
  this.side2 = s2;
  this.side3 = s3;
  this.side4 = s4;
}

var triangle = new Triangle(10, 8, 15);

console.log(Triangle.prototype); //Shows the Shape() function on console.
console.log(triangle.side1, triangle.side2, triangle.side3) //Shows the Triangle constructor works.
console.log(triangle.type); //Undefined


triangle.get_type();

var square = new Square(2, 2, 2, 2);
console.log(square.side1, square.side2, square.side3, square.side4);
console.log(square.type);
square.get_type();

try {
  triangle.getSomeValue();
} catch (e) {
  console.log(e.message);
}
try {
  square.getSomeValue();
} catch (e) {
  console.log(e.message);
}
Sreekanth
  • 3,110
  • 10
  • 22
  • 1
    What did you change and why? Code alone is not that helpful. **Explain** your solution so that others can **learn**. – Felix Kling Dec 07 '16 at 05:26