1

Could someone explain the difference between following inheritance implementations:

function Parent(name) {
    this.name = name;
    this.parentFoo = function() {
       //...
    }
}

function Child() {
    this.additional = true;
    Parent.apply(this, arguments); // Is it for copying parent fields to child object?
}

Child.prototype = Object.create(Parent.prototype);

and

function Parent(name) {
    this.name = name;
}

Parent.prototype.parentFoo = function() {
    //....
}

function Child() {
    this.additional = true;
    Parent.apply(this, arguments); // Is it for copying parent fields to child object?
}

Child.prototype = Object.create(Parent.prototype);

I mean what would be better to use, adding function to constructor directly or to prototype? I'm asking because

var childObj = new Child("Child name");
var parentObj = new Parent("Parent name");

childObj.foo();
parentObj.foo();

work well in both cases. Thank you!

3 Answers 3

1

In the first snippet, you're not storing your methods in the Parent's prototype, so cloning Parent's prototype for the Child class isn't doing anything. You're still able to call parentFoo from the child instances because you're running the parent constructor with the child as its context with Parent.apply(this, arguments); which runs

this.parentFoo = function() {
   //...
}

where the context this refers to the child instance.

I'm pretty sure re-defining and binding your methods in the constructor is not optimal.

In the second snippet, you're calling the constructor of the parent on the child, but you're not extending the parents prototype on the child class, so you won't be able to access the parentFoo method with instances of the child. You could fix that by adding the line from the first snippet:

Child.prototype = Object.create(Parent.prototype);

Edit: The difference between the two cases is in the first one, you're not using prototypical inheritence. You are cloning the parent prototype into the child's prototype, but you're not attaching any keys to the parent prototype. Instead you're redefining and directly binding each method to the instance in the parent constructor when you call Parent.apply(this, arguments); in the child's constructor.

Sign up to request clarification or add additional context in comments.

3 Comments

Of course, I have updated the second case. I have mentioned it from the very beginning.
So we have performance loss in the first case due to redefining and rebinding of each method, right?
@sidlejinks I believe so.
0

I believe the difference is the latter option (prototype) adds it to the signature of the object, but the former (using this) adds the function as a part of the memory footprint of the object. Therefore, in the latter option, the Parent object has parentFoo as part of it's definition, but in the former, each instance of the parent object has that function in memory.

Comments

0

See Learning JavaScript, especially class-like Constructor function and Property Inheritance through prototype/proto chaining and References therein.

Inheritance in JavaScript is usually done by Child.prototype=new Parent();.

// 'function' has "prototype" property by default.
// 'object' including 'function object' has "__proto__" property by default.

function Employee(){
   // Implicitly "this.__proto__=Employee.prototype;"
   this.name="empty";
   this.dept="general";
}
// By default, "Employee.prototype={__proto__:Object.prototype}"
// "(new Employee)={__proto__:Employee.prototype, name:"empty", dept:"general"}"
Employee.prototype.a="This is 'a' in Employee.prototype"; // Additional prototype 'a'.
// Then, "Employee.prototype={__proto__:Object.prototype, a:"Employee.prototype.a"}"


function Manager(){
   // Implicitly "this.__proto__=Manager.prototype;"
   this.reports=[];
}
// "(new Manager)={__proto__:Manager.prototype, reports:[]}"
Manager.prototype=new Employee;
// Then, "Manager.prototype={__proto__:Employee.prototype, name:"empty", dept:"general"}"

function WorkerBee(){
   // Implicitly "this.__proto__=WorkerBee.prototype;"
   this.projects=[];
}
// "(new WorkerBee)={__proto__:WorkerBee.prototype, projects:[]}"
WorkerBee.prototype=new Employee;
// Then, "WorkerBee.prototype={__proto__:Employee.prototype, name:"empty", dept:"general"}"


function SalesPerson(){
   // Implicitly "this.__proto__=SalesPerson.prototype;"
   this.dept="sales";
   this.quota=100;
}
// "(new SalesPerson)={__proto__:SalesPerson.prototype, dept:"sales", quota:100}"
SalesPerson.prototype=new WorkerBee;
// Then, "SalesPerson.prototype={__proto__:WorkerBee.prototype, projects:[]}"

function Engineer(){
   // Implicitly "this.__proto__=Engineer.prototype;"
   this.dept="engineering";
   this.machine="machine";
}
// "(new Engineer)={__proto__:Engineer.prototype, dept:"engineering", machine:""}"
Engineer.prototype=new WorkerBee;
// Then, "Engineer.prototype={__proto__:WorkerBee.prototype, projects:[]}"

2 Comments

Thank you for the detailed explanation! But I suppose in that case parent object's constructor is called also every time. What if we don't want it to be called?
@sidlejinks Child.prototype=new Parent(); parent object's constructor is called just once in the beginning.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.