javascriptclassecmascript-6

How can a superclass constructor call a method defined in the subclass that depends on a field being filled?


I am trying to build document indexes in JavaScript, and am having trouble figuring out the correct way to do work in a ES6 constructor.

The only solution I can figure is make users call buildIndex explicitly after construction - which seems counter intuitive and incorrect as if I need to call "construct" after construction.

Am I missing something or are ES6 constructors limited?


class TokenIndex {
    constructor(document, stemmer) {
        this.document = document;
        this.stemmer = stemmer || (x => x);
        this._buildIndex();
    }
    _buildIndex(){
        // do expensive index build
    }
}
class FilteredTokenIndex extends TokenIndex {
    constructor(document, stemmer, filter) {
        this.filterRegex = filter;
        // Fails because super must be called before `this`
        super(document, stemmer); 
    }
    _buildIndex(){
        // do expensive index build
    }    
}

class FilteredTokenIndex2 extends TokenIndex {
    constructor(document, stemmer, filter) {
        // Fails because builds the index without a filter
        super(document, stemmer); 
        this.filterRegex = filter;

    }
    _buildIndex(){
        // do expensive index build
    }    
}

Solution

  • The answer seems to be making use of the new.target, to identify if this is the actual class being constructed, or a parent and only executing the real work when they match. Finally found the answer in this mozilla article:

    https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/

    class TokenIndex {
      constructor(document, stemmer) {
        this.document = document;
        this.stemmer = stemmer || (x => x);
        if (new.target == TokenIndex){
          this._buildIndex();
        }
      }
      _buildIndex(){
        console.log('Build TokenIndex') // do expensive index build
      }
    }
    class FilteredTokenIndex extends TokenIndex {
      constructor(document, stemmer, filter) {
        super(document, stemmer); 
        this.filterRegex = filter;
        if (new.target == FilteredTokenIndex){
          this._buildIndex();
        }
      }
      _buildIndex(){
        // do expensive index build
        console.log('Build FilteredTokenIndex')
      }    
    }
    
    
    var ti = new TokenIndex(); // prints Build TokenIndex
    var fti = new FilteredTokenIndex(); // prints Build FilteredTokenIndex
    

    Thanks