How to access a method from the parent prototype in the child as we can with classes?
In a class when we have a method in the parent class we can access the same in the child class. In the prototype way of doing the same, I'm not able to access the parent prototype method
With class:
class Person {
constructor(name, id){
this.name = name;
this.id = id;
}
printDetails (){
console.log(`Printing details in parent class :${this.name} : ${this.id}`);
}
}
class Employee extends Person {
constructor(name, id, salary){
super(name, id);
this.salary = salary;
}
employeeInfo(){ // this will exist in the prototype of Employee class, not in the instance.
return `${this.name} : ${this.id} : ${this.salary}`
}
}
const a = new Employee('Mary', 1, 123456);
// console.log(a.employeeInfo())
// a.printDetails();
With Function and prototype:
let PersonF = function(name, id){
this.name = name;
this.id = id;
}
PersonF.prototype.getDetails = function(){ // Dont use arrow here, the this for the arrow is window, not the this of the object
console.log(`Printing details in parent in function way :${this.name} : ${this.id}`);
}
let pers = new PersonF('Person', 111);
// pers.getDetails();
let EmployeeF = function(name, id, salary){
PersonF.call(this, name, id); // this is same as super in class. here first param will take the this of the context and then other params
this.salary = salary;
}
Object.setPrototypeOf(EmployeeF, PersonF.prototype); // This is same as extends in class.
EmployeeF.prototype.printDetails = function(){
console.log(`${this.name} : ${this.id} : ${this.salary}`);
}
const emp = new EmployeeF('John', 1 , 10000000);
// emp.printDetails();
emp.getDetails(); // Getting an error here.
You can make sure, that EmployeeFinherits it's prototype from PersonF by using Object.create with PersonFs Prototype:
EmployeeF.prototype = Object.create(PersonF.prototype)
let PersonF = function(name, id){
this.name = name;
this.id = id;
}
PersonF.prototype.getDetails = function(){
console.log(`Printing details in parent in function way :${this.name} : ${this.id}`, this); // added log of `this`
}
let pers = new PersonF('Person', 111);
let EmployeeF = function(name, id, salary){
PersonF.call(this, name, id);
this.salary = salary;
}
EmployeeF.prototype = Object.create(PersonF.prototype) // create Employees Prototype from Persons
EmployeeF.prototype.printDetails = function(){
console.log(`${this.name} : ${this.id} : ${this.salary}`);
}
const emp = new EmployeeF('John', 1 , 10000000)
emp.getDetails();
This is also (part of) what Babel does when you target <IE10:
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
Object.defineProperty(subClass, "prototype", {
writable: false
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
Your problem is :
Object.setPrototypeOf(EmployeeF, PersonF.prototype);
This method is made for objects used as instances, and not objects used as classes; it actually sets the __proto__ attribute – for instances –, and not the prototype attribute of a class.
You can see this in this polyfill:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
Then, getDetails is actually accessible like this: EmployeeF.getDetails() (which calls behind the scene EmployeeF.__proto__getDetails().
I suggest you this:
function Person(name) {
this.name = name;
}
Person.prototype.print = function () {
console.log('I am', this.name);
}
function Employee(name, id) {
this.name = name;
this.id = id;
}
// What has changed !
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Person;
Employee.prototype.work = function() {
console.log(this.id, this.name, 'is working...');
}
var e = new Employee('Michel', 43);
e.print(); // 'I am Michel'
The objective here, is to say "The prototype of the prototype of Employee is the prototype of Person", ie Employee.prototype.prototype = Person.prototype.
Why prototype.prototype ?
Because the prototype of Employee must contains the inheritable methods of Employee, not Person's ones; so the inherited methods of Person will be at the NEXT prototype in the prototypes chain.
Object.create(a_prototype); return an empty object, but sets the prototype of this object to a_prototype.
So, first, we create the prototype of Employee to an empty object, but having Person.prototype as its prototype:
Employee.prototype = Object.create(Person.prototype);
Now, it remains just one problem: Employee.prototype has no constructor! Then, we simply add it via:
Employee.prototype.constructor = Person;
Thanks to this, we can see that Employee inherits from Person through Employee.prototype.constructor.
To see this, just try to print an instance of Person: the constructor is at person_instance.__proto__.constructor; then try to do the same thing with a new Employee, without the code above: no constructor in the prototype!
This is a simplified solution of what does TypeScript transpiler to convert classes from ES6 to ES5:
Object.setPrototypeOf(Employee, Person);
function PrototypeOfEmployee() {
this.constructor = Employee;
}
PrototypeOfEmployee.prototype = Person.prototype;
Employee.prototype = new PrototypeOfEmployee();