Search code examples
javascriptecmascript-5

Can you get the dervied class from the base class in JavaScript?


The following demonstrates what I am trying to achieve. I have a base class called X that does nothing to start with...

function X() {
}

I declare a derived class called Y that inherits from X. It also sets a property on the derived class called name. This is not meant to be for every instance and hence placed on the class itself.

function Y() {
  X.call(this);
}

Y.prototype = new X();
Y.name = 'Y';

We add another derived class called Z that comes from X. This time it sets a different value to the name property.

function Z() {
  X.call(this);
}

Z.prototype = new X();
Z.name = 'Z';

Now, from the actual base class I want to be able to test for and use the name property of any derived class. I cannot find a way to achieve this. So ideally it would work like this...

function X() {
    console.log(???.name);
}

Of course, I have no idea what to put in the ??? to get the actual derived class instance when the base class constructor is called. Maybe it is impossible?

Even better would be the ability to walk the class chain to if there is a class derived from Y or Z I can get all the intermediate values of name as well. If this is impossible then can you suggest an alternative approach?


Solution

  • First, subclass properly, restoring the constructor:

    function X() {}
    
    function Y() {
      X.call(this);
    }
    Y.prototype = Object.create(X.prototype);
    Y.prototype.constructor = Y;
    Y.name = 'Y';
    
    function Z() {
      X.call(this);
    }
    Z.prototype = Object.create(X.prototype);
    Z.prototype.constructor = Z;
    Z.name = 'Z';
    

    Then you can use this.constructor.name.

    function X() {
      this.theName = this.constructor.name;
    }
    
    function Y() {
      X.call(this);
    }
    Y.prototype = Object.create(X.prototype);
    Y.prototype.constructor = Y;
    Y.name = 'Y';
    
    function Z() {
      X.call(this);
    }
    Z.prototype = Object.create(X.prototype);
    Z.prototype.constructor = Z;
    Z.name = 'Z';
    
    document.write(new Y().theName + '<br />' + new Z().theName);

    Note you may have problems using the name property. Some time ago some browsers implemented a non-standard non-writable name property in functions. ES6 standardized it and now it's writable, but you could have problems on old browsers.

    So it may be better using another name, or storing it in the prototype.

    function X() {
      this.theName = this.name;
    }
    
    function Y() {
      X.call(this);
    }
    Y.prototype = Object.create(X.prototype);
    Y.prototype.constructor = Y;
    Y.prototype.name = 'Y';
    
    function Z() {
      X.call(this);
    }
    Z.prototype = Object.create(X.prototype);
    Z.prototype.constructor = Z;
    Z.prototype.name = 'Z';
    
    document.write(new Y().theName + '<br />' + new Z().theName);