2

I have a Shape class and a Circle class that inherits from the Shape class.

Shape.js

function Shape(id, name, color) {

    this.id = id;
    this.name = name;
    this.color = color;

    Shape.prototype.getDisplayName = () => {
        return this.id + ":" + this.name;
    }
};

module.exports = Shape;

Circle.js

const Shape = require('./shape');

Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;

function Circle(id, name, color, radius) {
    Shape.call(this, id, name, color);

    this.radius = radius;
};

module.exports = Circle;

This works fine, but when I have more than one Circle object, the getDisplayName function is using the wrong context.

app.get('/', async (req, res) => {

    let circle1 = new Circle('id1', 'Circle', 'red', 5);
    let circle2 = new Circle('id3', 'Circle', 'blue', 12);

    let shapes = [circle1, circle2];

    for(let shape in shapes){
        console.log(shapes[shape].getDisplayName());
    }

});

This prints out

id3:Circle
id3:Circle

I found a SO answer that gave a bit of help. By adding this.getDisplayName = this.getDisplayName.bind(this) to the Circle constructor, it works. However, I'd prefer not having to do this for every parent method on every child. Is there a better way?

Spark323
  • 1,525
  • 2
  • 16
  • 27
  • [Never assign `.prototype` methods inside the constructor!](https://stackoverflow.com/questions/28255957/assigning-prototype-methods-inside-the-constructor-function-why-not) – Bergi Jan 01 '19 at 21:20

1 Answers1

2

You can't assign to the prototype inside the constructor like that with an arrow function. All the instances will share the same prototype. You are creating a new arrow function on each call of the constructor where this is bound to the current instant. The result is this is set tot the last instance created for all instances.

You need to use a traditional function to allow this to bind to the correct object when the function is called.

Also, there's no reason to put it in the constructor. You only need to create this function once, not every time the constructor is called.

"use strict";

function Shape(id, name, color) {
  this.id = id;
  this.name = name;
  this.color = color;
};

Shape.prototype.getDisplayName = function() {
  return this.id + ":" + this.name;
}

Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;

function Circle(id, name, color, radius) {
  Shape.call(this, id, name, color);
  this.radius = radius;
};

let circle1 = new Circle('id1', 'Circle', 'red', 5);
let circle2 = new Circle('id3', 'Circle', 'blue', 12);

let shapes = [circle1, circle2];

for (let shape in shapes) {
  console.log(shapes[shape].getDisplayName());
}
Mark
  • 90,562
  • 7
  • 108
  • 148