javascript: Extened destroy method doesn't get called but super does get called

Viewed 116

Why isn't my destroy method in my extended class get called but my super destroy method does? And could you get my example to work that way please;

function MyClass(name, age) {
  this.name = name;
  
  this.destroy = function() {
    console.log('Super Class Destroy Method');
  }
  
  if(age == undefined) {
    return null;
  }
  
  return new MyClass2(name, age);
}

class MyClass2 extends MyClass {
  
  constructor(...args) {
    super(args[0]);
    
    this.age = args[1];
  }
  
  destroy() {
    super.destroy();
    
    console.log('Extedned Destroy Method');
  }
}


var myObj = MyClass('John Doe', 9);

myObj.destroy();

1 Answers

In the parent class, in the constructor, you do:

  this.destroy = function() {
    console.log('Super Class Destroy Method');
  }

This puts the destroy method directly on the instance. In contrast, in the child class:

  destroy() {
    super.destroy();
    
    console.log('Extedned Destroy Method');
  }

This destroy method is on the prototype.

This is what the prototype chain looks like, for a child instance:

instance <- MyClass2.prototype <- MyClass.prototype <- Object.prototype

If you instantiate a child, the parent's constructor will assign to a property of the instance when you do this.destroy =, so super.destroy() won't work (the superclass has no destroy method on its prototype).

So, change the superclass destroy to an actual method on the prototype.

function MyClass(name, age) {
  this.name = name;

  if (age == undefined) {
    return null;
  }

  return new MyClass2(name, age);
}
MyClass.prototype.destroy = function() {
  console.log('Super Class Destroy Method');
}

class MyClass2 extends MyClass {

  constructor(...args) {
    super(args[0]);

    this.age = args[1];
  }

  destroy() {
    super.destroy();

    console.log('Extedned Destroy Method');
  }
}


var myObj = new MyClass('John Doe', 9);

myObj.destroy();

Though, it's pretty odd to use both function and class syntax together, consider using just class instead:

class Parent {
  constructor(name, age) {
    this.name = name;
    return age === undefined ? null : new Child(name, age);
  }
  destroy() {
    console.log('Super Class Destroy Method');
  }
}

class Child extends Parent {
  constructor(...args) {
    super(args[0]);
    this.age = args[1];
  }
  destroy() {
    super.destroy();
    console.log('Extedned Destroy Method');
  }
}

var myObj = new Parent('John Doe', 9);
myObj.destroy();

Also, the return null in case no age is passed doesn't work because when you call a function with new, an object will be returned regardless; return null will still return an instance of the parent. Consider calling a function to create the object, not a constructor, before verification - or, throw an error if the argument is invalid:

class Parent {
  constructor(name, age) {
    this.name = name;
    if (Object.getPrototypeOf(this) === Parent.prototype) {
      // avoid stack overflow
      return new Child(name, age);
    }
  }
  destroy() {
    console.log('Super Class Destroy Method');
  }
}

class Child extends Parent {
  constructor(...args) {
    super(args[0]);
    this.age = args[1];
  }
  destroy() {
    super.destroy();
    console.log('Extedned Destroy Method');
  }
}

const makeParent = (name, age) => age === undefined ? null : new Parent(name, age);
const myObj = makeParent('John Doe', 9);
myObj.destroy();

Related