Inherited method does not inherit this. Why or what's wrong?

I have been learning and practicing JavaScript Classes (for information: I am currently working on the Build a Library project on my own computer).

I find this topic very fascinating and empowering. Nevertheless, there is one aspect that is troubling me, and it could be a gap on my understanding or simply my wrong approach. Please tell me frankly if that’s the case.

Now, to the question: when I use a static method in a class, and then I use that method in another class’ constructor (yes, I know that static methods should not be used on instances, but I use the instance as the arg instead), the this doesn’t want to be inherited, it seems :slight_smile: Am I getting it wrong?

Now, to make it easier for you to understand what I’m asking about, here’s a simplified example of what I’m trying to do on a larger project:

// This would be the Utils class with static methods
class AnimalsUtils {
    static printName(animal){  
        console.log(animal.name);
    }

    static printAll(animal){
        let message = [];
        for (const feature in animal) {
            if (Object.hasOwnProperty.call(animal, feature)) {
                message.push(`${feature}: ${animal[feature]}`);
            }
        }
        const output = message.join(', ');
        console.log(output);
        /* return message.join(', '); */
    }
}

// Now the parent class:
class Animal {
    constructor (name){
        this.name = name;
        this.sings = true;
        this.feet = 2;
        this.wings = 'none';
        this.init();
        // tried 3 ways
        // a) Including the AnimalsUtils.printAll(this); in this constructor.
        // Like: constructor(name){
        // ...
        // AnimalsUtils.printAll(this);
        // }
        // b) Like above, creating a method that calls the Utils, 
        // which is called at the time of instantiation from the constructor.
        // c) Including a this.init property in the constructor that equals 
        // to the return of AnimalsUtils.printAll(this);
        // constructor(name){
        // ...
        // this.init = AnimalsUtils.printAll(this);
        // }
        // In all cases same problem: The 'this' is not passed down
        // to the instance (the dog, or bird, etc), 
        // it only prints the properties requested from the parent class. 
        // For example, 'friendliness' is never printed (or returned)

        // The only way I got it to work the way I want
        // is declaring again on each child the init method
        // OR calling the AnimalsUtils.printAll from each child constructor.
        // Is that the only way? Am I doing something wrong?
        // Or maybe something in my approach is not right?
    }

    printName(){
        console.log(this.name);
    }

    init(){
        AnimalsUtils.printAll(this); // This is the this I mean (pun accidental)
    }
}

class Dog extends Animal {
    constructor(name){
        super(name);
        this.feet = 4;
        this.sings = false;
        this.barks = true;
        this.friendliness = 9;
    }
}

class Bird extends Animal {
    constructor(name){
        super(name);
        this.sings = true;
        this.friendliness = 2;
        this.flies = 'A lot!';
    }
}

// Instantiation (with Utils call included)
const rupert = new Dog('Rupert');
const olivier = new Bird('Olivier');
const random = new Animal('Random Species');

Maybe you can paste this code in VSC or similar and it may be easier to read :slight_smile:

I would really appreciate any informative and frank input regarding my questions in the code comments.

Thanks in advance!

Your problem here is to do with the order of the code being executed. Let’s take Rupert the Dog for example. When rupert is created, it goes to the constructor for Dog. The first thing called is the super() method, this then goes to the constructor for Animal. Inside this constructor the first few properties are created, and then this.init() is called, printing out your properties created so far. This then concludes the super() method, and it then proceeds through the rest of the Dog constructor creating your new methods. We can see this with some console.log's:

class Animal {
      constructor (name){
          this.name = name;
          this.sings = true;
          this.feet = 2;
          this.wings = 'none';
          console.log('test1')
          this.init();
      }
  
      printName(){
          console.log(this.name);
      }
  
      init(){
          AnimalsUtils.printAll(this); // This is the this I mean (pun accidental)
      }
  }

class Dog extends Animal {
      constructor(name){
            console.log('test2')
          super(name);
          console.log('test3')
          this.feet = 4;
          this.sings = false;
          this.barks = true;
          this.friendliness = 9;
      }
  }

const rupert = new Dog('Rupert');
# prints test2, test1 then test3, and then (name: Rupert, sings: false, feet: 4, wings: none)

We can see that ‘test1’ is printed before ‘test3’ meaning that your init() method is called before the child exclusive properties can be created. This can be remedied by simply including the call at the end of the child constructors instead.

  class Dog extends Animal {
      constructor(name){
          super(name);
          this.feet = 4;
          this.sings = false;
          this.barks = true;
          this.friendliness = 9;
          this.init()
      }
  }
  
const rupert = new Dog('Rupert');
# prints name: Rupert, sings: false, feet: 4, wings: none, barks: true, friendliness: 9

Hopefully this makes sense, if you want me to go over anything else let me know!

1 Like

First of all, huge thanks @adamgaffney96 for taking the time to go through this and do so with such clarity! :beers: :+1:

That’s exactly what I meant! Many hours and tests later I decided to post the question here. And your patient explanation is crystal-clear. Don’t think I’ll be confused with this one again. :smiley:

Thanks a bunch once more!

1 Like