HalfWebDev
HalfWebDev

Reputation: 7648

How does property lookups after calling super() in subclass actually work

I've a simple example from MDN.

class Animal { 


 constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(this.name + ' barks.');
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

Now, in subclass Dog how does this.name works under the hood. Since this refers to Dog class instance and name is not something which exists on Dog instance. So to access that we use super call which invokes parent's constructor. I get that it looks up.

But can someone please explain via the prototype mechanism (I'm comfortable in understanding the prototype lookup and chaining mechanism).

I'm sure deep down it will boil down to that but not clear about intermediate steps in between. Thanks!

Upvotes: 0

Views: 43

Answers (2)

HalfWebDev
HalfWebDev

Reputation: 7648

Actually, what I wanted to ask was under the hood. So, here's the answer based on @Jai's pointer in comments that I was looking for.

I ran the class based code through es5compiler or any compiler and got this conversion

var Dog = /** @class */ (function (_super) {

  __extends(Dog, _super);
    function Dog(name) {
        return _super.call(this, name) || this;
    }
    Dog.prototype.speak = function () {
        console.log(this.name + ' barks.');
    };
    return Dog;
}(Animal));

So basically

return _super.call(this, name) inside Dog function explains the confusion of this reference inside speak method of class Dog. It changes the context through call()

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 371019

this refers to Dog class

No, this refers to the instantiated object. The instantiated object has an internal prototype of Dog.prototype, and Dog.prototype has an internal prototype of Animal.prototype.

Since this refers directly to the instantiated object (in both constructors, and in all of the methods),

this.name = name;

puts the name property directly on that object, so it's completely fine to reference d.name, or, inside one of the methods, this.name:

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(this.name + ' barks.');
  }
}

const d = new Dog('Mitzie');

const dProto = Object.getPrototypeOf(d);
const secondProto = Object.getPrototypeOf(dProto);
console.log(dProto === Dog.prototype);
console.log(secondProto === Animal.prototype);

console.log(d.hasOwnProperty('name'));

Upvotes: 3

Related Questions