user5321531
user5321531

Reputation: 3265

Nested ES6 classes?

It seems possible to nest a class in a constructor which can then be instantiated from anywhere within the class, is this official?

[EDIT] E.g.,

class C {

    constructor() {
        class D {
            constructor() { }
        }
    }

    method() {
        var a = new D();  // works fine
    }

}

//var a = new D();  // fails in outer scope

The traceur generated JS https://google.github.io/traceur-compiler/demo/repl.html

$traceurRuntime.ModuleStore.getAnonymousModule(function() {
  "use strict";
  var C = function C() {
    var D = function D() {};
    ($traceurRuntime.createClass)(D, {}, {});
  };
  ($traceurRuntime.createClass)(C, {method: function() {
      var a = new D();
    }}, {});
  return {};
});
//# sourceURL=traceured.js

Upvotes: 94

Views: 102430

Answers (6)

JamesTheAwesomeDude
JamesTheAwesomeDude

Reputation: 1053

I don't understand why everyone's saying this is fundamentally impossible. What am I missing about this question?

class ParentClass {

    static SubClass = class SubClass { /* ... */ };

    static #SecretSubClass = class SecretSubClass { /* ... */ };

    constructor() {
        this.child = new ParentClass.SubClass();
        this.otherChild = new ParentClass.#SecretSubClass();
        console.log(`Created a new ${Object.getPrototypeOf(this).constructor.name}, which has a child of type ${Object.getPrototypeOf(this.child).constructor.name} and another child of type ${Object.getPrototypeOf(this.otherChild).constructor.name}`);
    }

}


new ParentClass();

Upvotes: 0

T.Todua
T.Todua

Reputation: 56371

Simpler:

class A {

    B = new (class {

        myMethod(){
            console.log('B method');
        }

    })();

}

However, seems that is not considered as a good pattern.

Upvotes: -1

Bergi
Bergi

Reputation: 664484

No, there are no nested class scopes in ES6, and there is no such thing as private members in the class syntax anyway if you mean that.

Of course you can put a second class as a static property on another class, like this:

class A {
    …
}
A.B = class {
    …
};

or you use an extra scope:

var C;
{
    class D {
        constructor() { }
    }
    C = class C {
        constructor() { }
        method() {
            var a = new D();  // works fine
        }
    }
}

(There seems to be a bug with traceur as it uses a hoisted var for the class declaration instead of block scope)


With the class field syntax, it will also be possible to write a single expression or declaration:

class A {
    …
    static B = class {
         …
    }
};

Upvotes: 118

ceving
ceving

Reputation: 23824

When you create a nested child class in a constructor of a parent class, this means every instance of the parent class has its own child class. Typically this is not what you want. Instead you want a child class, which is shared among all instances of the parent class. This means the nested class must be static. This is an example:

class Parent
{
  static Child = class Child {
    constructor (name) { console.log (`Child: ${name}`); }
  }
  
  constructor (...names) {
    console.log ('Parent');
    this.children = names.map (name => new Parent.Child (name));
  }
}

var p = new Parent ('Alice', 'Bob');

console.log (`same type? ${p.children[0].constructor === p.children[1].constructor}`);

Upvotes: 7

Ammatwain
Ammatwain

Reputation: 137

something like that?

class A {
    constructor () {
        this.B = class {
            echo () {
                console.log('I am B class');
            }
        }
    }
    echo () {
        this.b = new this.B;
        this.b.echo();
    }
}

var a = new A;

a.echo();

Upvotes: 10

user2530580
user2530580

Reputation: 157

You could use a getter:

class Huffman {
  constructor() { /* ... */ }
  static get Node() {
    return class Node {
      constructor() {  
        var API = this;
        API.symbol = 0; API.weight = 0;
        return API;    
      }
    };
  }
  get Node() {
    return Huffman.Node;
  }
  encode() { /* ... */ }
  decode() { /* ... */ }
  /* ... */
}

// usage
huffman = new Huffman;
new huffman.Node;
new Huffman.Node;

Which in latest Chrome Dev 44.0.2376.0 on Apple 10.10.2 gives in console

  • new huffman.Node
  • Node {symbol: 0, weight: 0}
  • new Huffman.Node
  • Node {symbol: 0, weight: 0}

In other news, getters are the secret sauce that let's you do a whole bunch of cool things in ES6.

Please Note The above construction breaks instanceof for Node (why? because a whole new class is defined with every get call). To not break instanceof define Node outside of the scope of a single getter, either in the constructor (disabling the Huffman.Node class property and causing instanceof to work within the namespace of a single Huffman instance, and break outside that), or define Node in a sibling or ancestor scope to Huffman (allowing instanceof to work in all scopes below that the one where Node is defined).

Upvotes: 8

Related Questions