Ideally I would like to do something like the following:
class Chess = {
constructor() {
this.board = ...;
...
};
class Square = {
constructor(row, col) {
this.row = row;
this.col = col;
};
};
My main motivation is that with the Chess and Square classes defined separately something like: (this referring to the Chess class)
this.empty(square)
could be shortened to
square.empty()
which is more readable and more concise.
Unfortunately I can't just make a
Square.empty()
method since the results depends on the information in the Chess class and
square.empty(chess)
is no real improvement.
The reason I have a Square class is that something like
square.up()
seems much nicer than something like
[row, col + 1]
Do you have a suggestion on how I would accomplish the above? Some way to write a class within a class or something else entirely?
EDIT:
Following the advice from likle and alex I did the following:
I added a context property to the Class Square
class Square = {
constructor(context, row, col) {
this.context = context;
this.row = row;
this.col = col;
};
};
Then redefined some methods from the Chess.prototype to the Square.protoype. For example:
// before
Chess.prototype.empty = function (square) {
return this.piece(square) === 0;
};
// after
Square.prototype.empty = function () {
return this.piece() === 0;
};
Which meant that every time I created a Square object I need to add context. For example:
new Square(3, 4); // before
new Square(this, 3, 4); // after
new Square(this.context, 3, 4); // sometimes like this
To make the code more readable I created the following method:
Chess.prototype.createSquare = function (row, col) {
return new Square(this, row, col);
};
So a Square object can sometimes be created with
this.createSquare(3, 4);
One may argue that JavaScript does not have "nested" classes as such -- there is no way for a class to use parent class scope, for instance, nor would it be meaningful for anything but parent class properties (static
declarations), but a class in JavaScript is just an object like any other, so you may as well define one and refer to it with a property on another class:
class Chess {
}
Chess.Square = class {
};
(yes, a name for a class is optional)
Then you can do things like:
new Chess.Square();
And generally everything else you do with a class or objects of a class.
What JavaScript can let you do is to have nested constructors. Even with above notation, a JavaScript class is essentially its constructor -- Chess.prototype.constructor === Chess
. Put another way, classes "decay" into constructor functions at runtime. Well, there is some extra metadata associated with them by ECMAScript and some differences, but the following is an example of nesting constructors to access outer scope:
function Chess() {
const chess = this;
function Square() { /// Obviously, this function/constructor/class is only available to expressions and statements in the Chess function/constructor/class (and if explicitly "shared" with other code).
Chess; /// Refers to the outer constructor/class -- you can do `new Chess()` etc
this; /// Refers to this Square object being created
chess; /// Refers to what `chess` declared outside this method, refers to at the time of creating this Square object
}
}
The above uses what is known as "closures", which is where you also need to know how scoping works in JavaScript. In Java, the Chess
class as specified above is known as a nested instance class, as opposed to a nested static class. The first example using class
keyword does specify a form of the latter, though (a static class).
The thing with JavaScript is that it's actually more flexible than what the traditional OOP model describes, and "nested classes" can mean different things, to different people, and in different programs. But the language evidently allows you do a lot of things which may help you implement your intended model or make your code hard to read (especially to people who don't know as much JavaScript as you) and debug. It's a trade-off one needs to address before going all in with nested classes.
Currently, there are no nested classes. What you could do is to have to two separate classes, Chess
and ChessSquare
- and have a reference to the chess passed in the constructor of the ChessSquare
and keep that stored as a property. This way you won't have to pass it in the methods of the ChessSquare
:
class ChessSquare = {
constructor(chess, row, col) {
this.chess = chess;
this.row = row;
this.col = col;
}
empty() {
// "this.chess" references the chess, and "this" references the square.
}
};
You probably want to create all instances of ChessSquare
within the Chess
class itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With