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 accessing parent class properties (static elements).
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 -- above, the Square property on Chess refers to a class without name; not necessarily great for debugging and introspection, but just illustrating a point here)
Having the above, you can do things like:
new Chess.Square();
And generally everything else you do with a class or objects of a class -- new simply expects a function that will act as a constructor, and class declarations actually "decay" into constructor functions when program is run -- values of all of the following expressions are true:
Chess instanceof Function;
typeof Chess == "function";
Chess.Square instanceof Function;
typeof Chess.Square == "function";
Chess.prototype.constructor == Chess;
Chess.Square.prototype.constructor == Chess.Square;
So have nested constructors, then -- now that we've established that a JavaScript class is essentially its constructor. Well, there is some extra metadata associated with every class by ECMAScript, and some differences, but it has no negative implications on being able to nest 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 kind of require you to have a good grasp on how scoping works in JavaScript. In Java, the Square class as specified above, would be known as a nested instance class, as opposed to a nested static class. The first example at the very top of the answer, using class keyword, does specify a form of the latter, though (a "static" class).
Here is yet another way to define an "instance" class Square:
class Chess {
constructor() {
this.Square = class {
constructor() {
/// Be vigilant about `this` though -- in every function (except arrow functions) `this` is re-bound, meaning `this` in this constructor refers to an instance of the anonymous class, not to an instance of the `Chess` class; if you want to access the latter instance, you must have a reference to it saved for this constructor to access, e.g. with the `const chess = this;` statement in `Chess` constructor somewhere
}
}; /// Every `Chess` object gets a _distinct_ anonymous class referred to with a property named `Square`; is a class for every object expensive? is it needed? is it useful?
}
}
The thing with JavaScript is that it, for better or worse, makes it possible to implement OOP in a bit more than one way, certainly more so than some of the other "OOP languages" allow, and "nested classes" can mean different things, to different people, and in different programs. This is known as "having a lot of rope to hang yourself with" -- a lot of facility that may either help you implement your intended model elegantly, and/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".