0

I have a question about a code demonstrating inheritance in javascript. The code is based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

You can see live demo here: https://jsfiddle.net/gk6xar8w/3/

Here's the code:

// Shape - superclass
function Shape() {
  this.x = 1;
  this.y = 2;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.',this.x,this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
  console.log("###### Inside Rectangle.constructor ######");
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 2); // Outputs, 'Shape moved. 2, 4'
rect.move(1, 2); // Outputs, 'Shape moved. 3, 6'

I have two questions.

Firstly, I'm not sure what the effect of Rectangle.prototype.constructor = Rectangle is. Even when I comment this line out, I still get same output. To help me understand I am logging "#### Inside Rectangle.constructor #####" inside function Rectangle() {...}. But this logs even when I comment out Rectangle.prototype.constructor = Rectangle.

Secondly, last two lines which both are rect.move(1, 2), they don't behave as I expected. First invocation outputs 2, 4 and the second outputs 3, 6.

We start with this.x = 1 and this.y = 2 defined inside parent class. First time we invoke rect.move(1,2) it adds for x: 1+1=2 and y: 2+2=4 as expected. But second time around, it doesn't x: 2+2=4 and y: 4+4=8 as expected. Instead it keeps the initial values of this.x = 1 and this.y = 2 and does x: 1+2=3 and y: 2+4=6.

It would be great if I can fix the code so that first invocation of rect.move(1,2) outputs 2, 4 and second invocation ouputs 4, 8 and third outputs 8, 16 and so on.

Thanks.

8
  • 1
    Both times, you're asking it to move (1, 2). I'm not sure why you expect the results to be different Commented Jul 13, 2020 at 2:00
  • I want to do multiple moves and values of x and y to persist. If we do move(1,2) more than once they give different values in this case. Commented Jul 13, 2020 at 2:01
  • To answer your first question, see developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Jul 13, 2020 at 2:01
  • 1
    The values of x and y are persisting. Break it down; start with x: 1, y: 2, then add (1, 2) so that's x: 1 + 1 = 2 and y: 2 + 2 = 4. The values are now x: 2, y: 4. Then add (1, 2) again so it's x: 2 + 1 = 3 and y: 4 + 2 = 6 Commented Jul 13, 2020 at 2:03
  • 1
    I'll ask again, why would you expect them to be different? Please edit your question to explain what you think they should be and why you think that Commented Jul 13, 2020 at 2:05

2 Answers 2

2

As for your first question, Rectangle.prototype.constructor = Rectangle has no effect. That line sets the constructor of the Rectangle class but the Rectangle() function is already the constructor, so there is no effect.

For your second question, the move function changes the x value of the object by the x value passed into the function. Same goes for the y value. 2+1=3 and 4+2=6

If you want the x and y values to double each time, you could use this function:

Shape.prototype.move = function() {
    this.x += this.x; // <-- uses this.x instead of x parameter
    this.y += this.y; // <-- uses this.y instead of y parameter
    console.info('Shape moved.',this.x,this.y);
};
Sign up to request clarification or add additional context in comments.

2 Comments

What's the point in passing in x and y values to move if they're never used?
Right. They should probably be removed then
0

I understand now.

// Shape - superclass
function Shape() {
  this.x = 1;
  this.y = 2;
}

// superclass method
Shape.prototype.move = function() {
  this.x += this.x;
  this.y += this.y;
  console.info('Shape moved.',this.x,this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
  console.log("###### Inside Rectangle.constructor ######");
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(); // Outputs, 'Shape moved.'
rect.move(); // Outputs, 'Shape moved.'

This outputs 1,2 -> 2,4 -> 4,8 -> ... and requires no arguments to move().

In the original code, this.x and this.y persist. Sorry for the confusion and thanks a lot.

Here's a working code:

// Shape - superclass
function Shape() {
  this.x = 1;
  this.y = 2;
}

// superclass method
Shape.prototype.move = function(a) {
  this.x = this.x + a;
  this.y = this.y + a;
  console.info('Shape moved.',this.x,this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
  console.log("###### Inside Rectangle.constructor ######");
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(3); // x: 4, y: 5
rect.move(3); // x: 7, y: 8
rect.move(3); // x: 10, y: 11

Note that this.x and this.y are persistent.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.