1

So, I'm quite new to Javascript, and I'm trying to learn some OOP principles in it.

I've run into a problem. So, I'm basically creating a scene graph for the HTML canvas, which means I need a recursive structure. Each node has to be able to contain an array of child nodes. So, say I have a base node object this like:

// Shape class (It is part of the BNBeagle namespace)
Shape: function () {
    this.children = [];
},

No problem.

Then, I go on to create my own subclass for a small sample game, it might be as such:

function PlayerShip() {
    // drawShape is a method that's overrided from the Shape class
    this.drawShape = function () {
    BNBeagle.canvasContext.fillStyle = "#FF0000";
    BNBeagle.canvasContext.fillRect(-25, -25, 50, 50);
    };
};

PlayerShip.prototype = new BNBeagle.Shape();

The problem I'm now facing is that, from what I've gathered from research, doing prototypal inheritance like this creates a problem when it comes to reference values such as arrays, which I quickly discovered. Basically, I found out that ALL my PlayerShip instances will share the very same "children" array from the prototype, which is obviously no good.

From what I've been able to found around the internet, the solution seems to be to override the property in the child class, basically by doing this:

function PlayerShip() {
    this.children = [];

    // drawShape is a method that's overrided from the Shape class
    this.drawShape = function () {
    BNBeagle.canvasContext.fillStyle = "#FF0000";
    BNBeagle.canvasContext.fillRect(-25, -25, 50, 50);
    };
};

Simply just by adding the children property for the PlayerShip. Now, this works all well and good, all instances of PlayerShip now has their own array. However, I'm just wondering if there's a more "user-friendly" way of doing this? Say that I am to release this basic framework later on for public use, how should people know exactly what properties to override in order to make the objects work as they should? It seems a bit silly.

I'm wondering if there's a way to do this without having to have subclassing override these types of reference values? :)

Thank you very much!

CodingBeagle
  • 1,888
  • 2
  • 24
  • 52
  • 2
    You might want to read [Benefits of using `Object.create` for inheritance](http://stackoverflow.com/q/17392857/218196). I also recommend to read the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript). – Felix Kling Mar 03 '15 at 20:34
  • 2
    See also [correct inheritance](http://stackoverflow.com/q/10898786/1048572). – Bergi Mar 03 '15 at 20:37

1 Answers1

2

Use Object.create to create a prototype object, which doesn’t call the constructor and so only includes the prototype:

PlayerShip.prototype = Object.create(BNBeagle.Shape.prototype);

Then you can call the parent constructor at the beginning of the child one:

function PlayerShip() {
    // Call parent constructor with appropriate `this`
    BNBeagle.Shape.call(this);

    // drawShape is a method that's overrided from the Shape class
    this.drawShape = function () {
        BNBeagle.canvasContext.fillStyle = "#FF0000";
        BNBeagle.canvasContext.fillRect(-25, -25, 50, 50);
    };
}
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • `drawShape` should probably be defined on `PlayerShip.prototype` though. – Felix Kling Mar 03 '15 at 20:35
  • Interesting! I did see the "call" method. Now, just to be clear, what exactly will the "call" method do for my class? Will it basically create its own copies of whatever properties I have in the shape class? – CodingBeagle Mar 03 '15 at 20:35
  • 2
    @Bitious: `call` executes the function and sets its `this` value to the first argument passed to it. I.e. everything that happens to `this` inside `BNBeagle.Shape` will happen to the new `PlayerShip` instance. – Felix Kling Mar 03 '15 at 20:36
  • @FelixKling Oooh, thanks, I see then! Makes sense now :-) I will accept the answer in about 5 minutes, when I'm allowed to do so by Stackoverflow. – CodingBeagle Mar 03 '15 at 20:37