20

I have a class, and another class that extends that class.

class Shape {
  constructor() {
    return this;
  }
}
class Circle extends Shape {
  constructor() {
    super();
    return this;
  }
}
let foo = new Circle();

I can get foo's class with

let className = foo.constructor.name 
// returns string 'Circle'

Is it possible to get the name of foo's superclass ('Shape') in a similar manner?

joelg
  • 357
  • 2
  • 11
  • 1
    `foo.__proto__.constructor.name`? I think `__proto__` has been standardized, even. – John Dvorak Jan 03 '16 at 01:50
  • 2
    That would give you a parent class but not necessarily the class the object was extending directly, or the one it extended originally. – joshstrike Jan 03 '16 at 01:58
  • Thanks Jan - that gives me the original class again, but foo.__proto__.__proto__.constructor.name gets it. – joelg Jan 03 '16 at 01:59
  • @joelg Yes but if you wanted to go further you would have to keep adding more __proto__ to it and then you would get an error when you hit Object. You might want to rephrase the question as to how to get the parent class. Assuming your class is not final, a child class would not get the same result. – joshstrike Jan 03 '16 at 02:22
  • 2
    @JanDvorak: `__proto__` has been standardized for JavaScript engines in web browsers only, purely as a backward-compatibility thing. Modern code should use `Object.getPrototypeOf`. – T.J. Crowder Feb 23 '16 at 11:42

4 Answers4

24
Object.getPrototypeOf(Object.getPrototypeOf(foo)).constructor.name;
dmx
  • 241
  • 2
  • 3
6

Got it:

let superClassName = foo.__proto__.__proto__.constructor.name
// return Shape

Edit: this returns the parent class, which is not necessarily the class Circle extended originally. In my use case they're the same, but there's subtle ambiguity about the meaning of 'superclass' here.

joelg
  • 357
  • 2
  • 11
  • 5
    `Object.getPrototypeOf` would be more standard than `__proto__`. – loganfsmyth Jan 03 '16 at 02:13
  • 1
    That's the immediate parent class, not necessarily the superclass you're looking for. – joshstrike Jan 03 '16 at 02:24
  • Ah, thanks. They're the same for me, but I can see that it's not necessarily the case. – joelg Jan 03 '16 at 02:31
  • 1
    @joelg: `__proto__` is defined only for JavaScript engines in web browsers, purely for backward-compatibility, and isn't present on all objects (although it's present on *the vast majority* of objects; basically, with `o = Object.create(null)`, `o` has no `__proto__` property because the `__proto__` property is defined by `Object.prototype`, which `o` doesn't use ). `Object.getPrototypeOf` is the correct way to get the prototype of an object. – T.J. Crowder Feb 23 '16 at 11:43
  • Down voted for asking a question and not really listening to the responses. This solution is for a very specific case, and not even a good solution – Russell Ormes Jan 25 '17 at 15:44
3

You could define the following class:

class MyObject
{
  extends(className)
  {
    let next = Object.getPrototypeOf(this);

    while(next.constructor.name !== "Object")
    {
      if(next.constructor.name === className)
        return true;
      next = Object.getPrototypeOf(next);
    }
    return false;
  }
}

Let each class defined by you extend that class.

Now if you want to check if your object extends a specific class, you can call it's extends method and pass the name of the parent class as argument. The extends method will walk up the whole inheritance tree and check if your object extends the given class checking not just his parents, but also his grand parents and grand grand parents and so on.

Example:

class MyObject
{
  extends(className)
  {
    let next = Object.getPrototypeOf(this);

    while(next.constructor.name !== "Object")
    {
      if(next.constructor.name === className)
        return true;
      next = Object.getPrototypeOf(next);
    }
    return false;
  }
}

class Vehicle extends MyObject
{
}

class Car extends Vehicle
{
}

class Bmw extends Car
{
}

let car = new Car();
let bmw = new Bmw();

console.log("bmw extends Bmw: " + bmw.extends("Bmw"));
console.log("bmw extends Car: " + bmw.extends("Car"));
console.log("bmw extends Vehicle: " + bmw.extends("Vehicle"));
console.log("car extends Car: " + car.extends("Car"));
console.log("car extends Bmw: " + car.extends("Bmw"));
Norby M.
  • 91
  • 1
  • 5
-3

Your ultimate superclass is always Object, so there's no point trying to derive it. You need to probe whether the instance in question is an instance of something else using the 'is' keyword. I'm writing this from an Actionscript-3 perspective so I'm not sure exactly what the syntax is in ES-6 but it should be along the lines of "if (this is Shape)". That would return true if the instance in question extends the class you're talking about, false otherwise.

However what you're asking is where Shape branches off the standard library or the standard Object, and there is no way the compiler or the runtime could figure that out. In theory it would be awfully nice if ECMA languages could give you a backwards array of inheritance for a given class, but AFAIK that is not and has never been a feature. Without the full chain of inheritance, you need to know what superclass you're looking for or you can't derive it in any logical way.

joshstrike
  • 1,753
  • 11
  • 15