2

In the following example the constructor function which creates a new node (here named Node) lies outside the class whose method calls it:

class Collection {

  constructor() {
    this.collection = [];
  };

  addNode(value) {
    const node = new Node(value);
    this.collection.push(node);
    console.log(this.collection);
  };
};

function Node(value) {
  this.value = value;
}

const col = new Collection();

col.addNode("foo");

However, I'd like to have the constructor function inside the class (mainly because it's only used by that class). This will fail (x is not a constructor):

class Collection {

  constructor() {
    this.collection = [];
  };

  Node(value) {
    this.value = value;
  };

  addNode(value) {
    const node = new this.Node(value);
    this.collection.push(node);
    console.log(this.collection);
  };
};

const col = new Collection();

col.addNode("foo");

I'm also aware that Javascript currently does not support nested classes. What I'm currently doing is simply declaring the Node constructor inside the addNode method.

But I'm curious: is it possible to have such constructor function iside the class that calls it?

  • "*I'm also aware that Javascript currently does not support nested classes*" - [are you sure about that](https://stackoverflow.com/a/28784501/1048572)? – Bergi Oct 24 '22 at 04:04
  • 1
    "*What I'm currently doing is simply declaring the `Node` constructor inside the `addNode` method.*" - please don't do that! This is creating a new, separate class every time the `addNode` method is called, you really don't want that. – Bergi Oct 24 '22 at 04:06
  • @Bergi thanks a lot for pointing that. But now I'm confused: you start your answer saying *"there are no nested classes in ES6"*. So, JS supports nested classes or not? (I'm specifically talking about a `class` keyword inside another class) –  Oct 24 '22 at 04:24
  • Interesting. Why is `this.Node` not a constructor? It certainly seems to be a function, and I was under the impression that any function could be a constructor. Am I wrong? – Wyck Oct 24 '22 at 04:25
  • 1
    @Wyck Class methods do not have an internal `[[Construct]]` property and cannot be invoked with `new`. – kelsny Oct 24 '22 at 04:27
  • @caTS I found [this answer to _How to check if a Javascript function is a constructor_](https://stackoverflow.com/a/40922715/1563833) which provides an explanation to supplement your comment. It explains why _Functions created via the arrow functions syntax or via a method definition in classes or object literals are not constructable._ – Wyck Oct 24 '22 at 04:47
  • @Megapteranovaeangliae I've edited the linked answer. What I meant was that you cannot just put a `class` declaration inside the body of a `class` and expect it to be available under the declared name in the methods of the outer class, which was what the OP was attempting to do. – Bergi Oct 24 '22 at 05:28

1 Answers1

2

Option 1: defining Node as an instance field and setting it to a function (basically your first example)

class Collection {

  constructor() {
    this.collection = [];
  };

  Node = function (value) {
    this.value = value;
  };

  addNode(value) {
    const node = new this.Node(value);
    this.collection.push(node);
    console.log(this.collection);
  };
};

const col = new Collection();

col.addNode("foo");

Option 2: using a nested class (which is also an instance field)

class Collection {

  constructor() {
    this.collection = [];
  };

  Node = class Node {
    constructor (value) {
      this.value = value;
    }
  }

  addNode(value) {
    const node = new this.Node(value);
    this.collection.push(node);
    console.log(this.collection);
  };
};

const col = new Collection();

col.addNode("foo");

Option 3: using either of the above, but making it a static field instead (recommended). This is so that the class is not re-created for every instance of Collection you create.

class Collection {

  constructor() {
    this.collection = [];
  };

  static Node = function (value) {
    this.value = value;
  };

  addNode(value) {
    const node = new Collection.Node(value);
    this.collection.push(node);
    console.log(this.collection);
  };
};

const col = new Collection();

col.addNode("foo");
kelsny
  • 23,009
  • 3
  • 19
  • 48