0

I am building a chess application and am running into an issue about the difference between object definition and instantiation in JavaScript. For example, I want to separate my Board model (and view) from its representation (a nested array) via a Matrix model:

var Matrix = function(n, m) {
    // builds an n*m nested array
    // e.g. a 2x3 array would look like this:
    // [[0, 0], [0, 0], [0, 0]]
};

// A setter, which takes a `Point` object and correctly updates the nested array
Matrix.prototype.set = function(pt, obj) {
    this.state[pt.y][pt.x] = obj;
};

// A custom `each` method that iterates over the nested array
Matrix.prototype.each = function(fn) {
  // executes `fn` against every (x,y) in the nested array
};

// etc.

And then Board looks like this:

var Board = function(n, m) {
    Matrix.call(this, n, m);

    // now use `Matrix`'s `set` method to place pieces on the board.
};

Board.prototype = Matrix.prototype;

// etc.

My issue is really in the definition of Board. When I instantiate a new Board object, I would like for it to subclass Matrix and then use Matrix's methods to set pieces on the board. But the problem is that Board does not have access to Matrix's methods at instantiation, because that relationship is still being defined.

Trying to resolve this issue has clarified the answer to this question. It seems like the problem is that Board isn't a real subclass of Matrix. That relationship is not set until the code actually executes. What is the JavaScript-esque way of handling this relationship?

Community
  • 1
  • 1
jds
  • 7,910
  • 11
  • 63
  • 101
  • 1
    `Board.prototype = Matrix.prototype;` is a bad idea. You want `Board.prototype = Object.create(Matrix.prototype);` (with a shim if necessary for the relevant subset of `Object.create`'s functionality). – T.J. Crowder Feb 10 '14 at 18:19

2 Answers2

2

But the problem is that Board does not have access to Matrix's methods at instantiation, because that relationship is still being defined.

No. When you use the new operator on Board, then first the relationship ("prototype chain") will be defined and after that the Board constructor function will be called on the new instance, where it can call the Matrix function on the instance or add instance properties like .state. You can use the prototypically inherited set method without any problems in there.

Looking at Why is inheritance only defined at compile-time?

In JavaScript, inheritance is set up at runtime. You can declare the function body (using inherited methods in it), then set the prototype, then instantiate objects.

Board.prototype = Matrix.prototype;

Don't do that. You want Board.prototype = Object.create(Matrix.prototype).

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 2
    I'm not seeing the reason for the downvotes on this, Bergi's quite correct about what happens when you actually try to *use* the `Board` constructor. – T.J. Crowder Feb 10 '14 at 18:21
  • I don't think this answer deserves downvotes. I assume that *"...the constructor will be called on the new instance*" refers to the `Matrix` constructor. – cookie monster Feb 10 '14 at 18:23
  • @cookiemonster: I did refer to the `Board` constructor, actually. It does call `Matrix`, sure. – Bergi Feb 10 '14 at 18:25
  • Certainly you're not saying: *"When you call new `Board`, then first the relationship ("prototype chain") will be defined and after that the `Board` constructor will be called on the new instance."* I assumed you were referring to `Matrix`. – cookie monster Feb 10 '14 at 18:27
  • @cookiemonster: Yes, that's what I'm saying. You might want to read the linked docs about [how the `new` operator works](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) :-) – Bergi Feb 10 '14 at 18:28
  • @Bergi: I know how `new` works. I was referring to your use of the word *"constructor"* in that sentence to clarify which one you were talking about. – cookie monster Feb 10 '14 at 18:29
  • OK, I did clarify it now :-) – Bergi Feb 10 '14 at 18:32
  • Yeah, I think your wording is confusing. It makes it sound like `Board` is invoked twice since `new Board` already is a call to `Board`. Whatever. Doesn't matter. – cookie monster Feb 10 '14 at 18:34
2

This is incorrect:

Board.prototype = Matrix.prototype;

Do this instead so that additions to Board.prototype don't affect Matrix.prototype.

Board.prototype = Object.create(Matrix.prototype);

Now Board.prototype is an empty object that inherits from Matrix.prototype.


I see no reason why your object created from Board won't have access to methods from Matrix.prototype, so I'd assume that you were perhaps overwriting or shadowing the Matrix.prototype methods.

The // etc. part of your code is likely the issue.

cookie monster
  • 10,671
  • 4
  • 31
  • 45