In the below code when I do console.log(teacher1.getDetails()); the property value shows undefined but when I do console.log(teacher1.personName) or console.log(teacher.mainSubject) it shows property value. What is happening here? What am I missing? Can somebody explain it please? And how to make it work?
let Person = function(personName, age) {
this.personName = personName;
this.age = age;
};
Person.prototype.getDetails = function() {
return `Person Name:${this.personName}. Age is ${this.age}.`;
};
//Child constructor function
let Teacher = function(personName, age, mainSubject) {
Person.call(this, personName, age);
this.mainSubject = mainSubject;
};
Teacher.prototype = Object.create(Person.prototype); //inheritance
Teacher.prototype.getDetails = function() {
return `${this.__proto__.getDetails()} Main subject is ${this.mainSubject}.`; //optionally invoke the parent method.
};
let teacher1 = new Teacher("Sakib", 35, "Physics");
console.log(teacher1.getDetails()); //invokes Teacher.getDetails() method (child's method).
You need to implement getDetails method in the Teacher class like this:
Teacher.prototype.getDetails = function() {
return `${Person.prototype.getDetails.call(this)} Main subject is ${this.mainSubject}.`;
}
Your implementation doesn't work because of next: you call the parent method regarding parent's context which doesn't have values defined because in Teacher constructor you define values regarding the child context.
Person.call(this, personName, age);
Working example:
let Person = function(personName, age) {
this.personName = personName;
this.age = age;
};
Person.prototype.getDetails = function() {
return `Person Name:${this.personName}. Age is ${this.age}.`;
};
//Child constructor function
let Teacher = function(personName, age, mainSubject) {
Person.call(this, personName, age);
this.mainSubject = mainSubject;
};
Teacher.prototype = Object.create(Person.prototype); //inheritance
Teacher.prototype.getDetails = function() {
return `${Person.prototype.getDetails.call(this)} Main subject is ${this.mainSubject}.`; //optionally invoke the parent method.
};
let teacher1 = new Teacher("Sakib", 35, "Physics");
console.log(teacher1.getDetails()); //invokes Teacher.getDetails() method (child's method).
Problems in your code:
this.__proto__.getDetails() doesn't directly calls the getDetails function defined in Person.prototype because in the first invocation of getDetails() function, this.__proto__ returns Teacher.prototype. As a result, this.__proto__.getDetails() invokes itself, i.e. Teacher.prototype.getDetails()
When Teacher.prototype.getDetails() is called for the second time, this.__proto__ now refers to Person.prototype because this is now Teacher.prototype and its prototype is Person.prototype.
The second call to Teacher.prototype.getDetails() invokes the Person.prototype.getDetails() function
You need to bind this to make sure that value of this inside Person.prototype.getDetails() is correct
You shouldn't use __proto__ - its deprecated. Use Object.getPrototypeOf() to get a prototype of an object
Fixed Code:
let Person = function(personName, age) {
this.personName = personName;
this.age = age;
};
Person.prototype.getDetails = function() {
return `Person Name:${this.personName}. Age is ${this.age}.`;
};
let Teacher = function(personName, age, mainSubject) {
Person.call(this, personName, age);
this.mainSubject = mainSubject;
};
Teacher.prototype = Object.create(Person.prototype);
Teacher.prototype.constructor = Teacher;
Teacher.prototype.getDetails = function() {
const personPrototype = Object.getPrototypeOf(Object.getPrototypeOf(this));
return `${personPrototype.getDetails.call(this)} Main subject is ${this.mainSubject}.`;
};
let teacher1 = new Teacher("Sakib", 35, "Physics");
console.log(teacher1.getDetails());