Javascript Inheritance ; call and prototype - javascript

To implement inheritance in Javascript, one generally does the following 2 steps;
Say I have a base class "Animal"
var Animal = function(name){
this.name = name;
}
I now want to derive a sub class "Dog" from the same. So I would say
var Dog = function(name) {
Animal.call(this,name);
}
So I am calling my parent class constructor from my derived class constructor.
The 2nd step is to set the prototype as follows;
Dog.prototype = new Animal();
Now I can access any of the base "Animal" class properties from within my derived class Dog.
So my question is why are these 2 steps necessary ?
If we just call the base class constructor using
Animal.call(this,name);
isn't that enough for implementing Inheritance ?
Why do we also need to set the prototype property using Dog.prototype = new Animal(); ?
I wanted to understand what each of the above 2 steps does ?

var Animal = function(name){
this.name = name;
}
Animal.prototype.sleep = function() {
console.log("Sleeping")
}
...
// Without this line:
Dog.prototype = new Animal();
// the following code will fail, since `d` does not contain `sleep`
d = new Dog();
d.sleep();
Animal.call(this,name); simply calls the function Animal, but using the same this as the calling function.
Dog.prototype = new Animal(); sets the prototype of the prototype. However, Dog.prototype = Object.create(Animal.prototype) might be more correct.

A code sample is worth a thousand words :)
var Animal = function(name) {
this.name = name;
}
Animal.prototype.run = function () {
// do something
};
var Dog = function(name) {
Animal.call(this, name);
}
var dog = new Dog('Puppy');
typeof dog.name; // "string"
typeof dog.run; // "undefined"
dog instanceof Animal; // false
dog instanceof Dog; // true
Dog.prototype = new Animal();
var dog = new Dog('Puppy');
typeof dog.name; // "string"
typeof dog.run; // "function"
dog instanceof Animal; // true
dog instanceof Dog; // true
As you can see, if you don't use Dog.prototype = new Animal();, Animal.prototype members won't be inherited. Moreover, Dog instances won't be considered as instances of Animal.

The first thing to understand is that in JavaScript there is no classical inheritance, the mechanism we know from C-languages like Java, C# and so fort. In JavaScript, code reuse can be accomplished by using prototypal-inheritance. The only thing we have is objects, blocks of code who are alive and don't need to be instantiated. For example: when a function is invoked on an object - like a method, the current object is inspected whether the function is known. If not found, the engine calls it prototype (which is an other object) and inspects whether the function name is known and can be invoked. When not found, íts prototype is called and so on. So, setting the prototype of a object one can orchestrate the prototype-chain.
To answer your question: nothing is necessary, its up to you what you want. Code reuse is what you want and inheritance is the way you can achieve this (Stoyan Stefanov - JavaScript Patterns). In JavaScript, more ways are available to reuse code.
Furthermore, this is bound to the current context, not always the current object.

There are no classes, nor subclasses, in javascript.
call and apply execute a function in the context of a different 'this'. What you have in your sample code is unneeded.
//Create your constructor function:
var Animal = function(){}
Animal.prototype = {
sleep: function(){
console.log('zzz');
},
bark: function(name){
console.log(name +' barks!');
}
}
var dog = new Animal();
dog.sleep();
dog.bark('asdasd');

Second step helps you to inherit prototype methods. Imagine that we have more complex class:
function Animal(name) {
this.name = name;
}
// shared method
Animal.prototype.say = function () {
alert( this.name );
};
function Dog() {
Animal.apply(this, arguments);
}
Dog.prototype = new Animal();
var dog = new Dog('Cooper');
// method has been inherited
dog.say(); // alerts 'Cooper'
You can try it here

Here we define the constructor function for Animal
var Animal = function(name){
this.name = name;
}
Then define the constructor function for Dog and from inside it we invoke the constructor function of Animal. Just like we do super() in class based object oriented design.
var Dog = function(name) {
Animal.call(this,name);
}
Then we build the prototype of Dog by consuming the methods defined in the prototype of
Animal. Here it does not clone methods in Animal , but a link is set between Dog and Animal using which it re uses the methods in Animal
Dog.prototype = new Animal();
And continue extending it adding more methods
Dog.prototype.showName = function(){
// do something
}

Related

How can I access a property of a constructor through an instance of that constructor?

Here the constructor is Animal. It has two instances duck and beagle. There is a function named eat() which is actually a prototype of Animal.
function Animal() {
this.color = "brown";
}
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log("nom nom nom");
}
};
let duck = Object.create(Animal.prototype);
let beagle = Object.create(Animal.prototype);
duck.eat();
console.log(duck.color);
here
duck.eat()
works, but duck must also inherit the color brown right ? Why am I not able to access it using
duck.color ?
There is no color property on Animal.prototype. It is dynamically added to the object when the constructor function is called… but you aren't calling the constructor function at all.
If you want to create an instance of a class, then call the constructor function. Don't use Object.create.
function Animal() {
this.color = "brown";
}
Animal.prototype = {
eat: function() {
console.log("nom nom nom");
}
};
let duck = new Animal();
let beagle = new Animal();
duck.eat();
console.log(duck.color);
No It wont inherit,
Please read the definition of Object.create.
"The Object.create() method creates a new object, using an existing object as the prototype of the newly created object"
Means, only prototype will be copied from existing object on will be placed in newly create object's prototype
Here color is instance variable not prototype. Hence wont be available in newly created duck object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

difference between different ways of prototypal inheritance [duplicate]

I've been trying to wrap my head around the new Object.create method which was introduced in ECMAScript 5.
Usually when I want to use inheritance I do something like this:
var Animal = function(name) { this.name = name; }
Animal.prototype.print = function() { console.log(this.name); }
var Dog = function()
{
return Animal.call(this, 'Dog');
}
Dog.prototype = new Animal();
Dog.prototype.bark = function() { console.log('bark'); }
I just assign a newly created Animal object to Dog's prototype and everything works like a charm:
var dog1 = new Dog();
dog1.print(); // prints 'Dog'
dog1.bark(); // prints 'bark'
dog1.name; //prints 'Dog'
but people(without explaining) are saying that Dog.prototype = new Animal(); is not the way inheritance works and that I should use Object.create approach:
Dog.prototype = Object.create(Animal.prototype);
which also works.
What's the benefit of using Object.create or am I missing something?
UPDATE: Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
In the following I assume you are only interested in why Object.create is preferable for setting up inheritance.
To understand the benefits, lets first clarify what a "class" is made of in JavaScript. You have two parts:
The constructor function. This function contains all the logic to create an instance of the "class", i.e. instance specific code.
The prototype object. This is the object the instance inherits from. It contains all methods (and other properties) that should be shared among all instances.
Inheritance establishes an is-a relation, for example, a Dog is an Animal. How is this expressed in terms of constructor function and prototype object?
Obviously a dog must have the same methods as an animal, that is the Dog prototype object must somehow incorporate the methods from the Animal prototype object. There are multiple ways to do this. You will often see this:
Dog.prototype = new Animal();
This works because an Animal instance inherits from the Animal prototype object. But it also implies that every dog inherits from one specific Animal instance. That seems to be a bit strange. Shouldn't instance specific code only be run in the constructor function? Suddenly instance specific code and prototype methods seem to be mixed.
We don't actually want to run Animal instance specific code at that moment, we only want all the methods from the Animal prototype object. That is what Object.create lets us do:
Dog.prototype = Object.create(Animal.prototype);
Here we are not creating a new Animal instance, we only get the prototype methods. The instance specific code is executed exactly where it should be, inside the constructor:
function Dog() {
Animal.call(this, 'Dog');
}
The biggest advantage is that Object.create will always work. Using new Animal() only works if the constructor does not expect any arguments. Imagine if the constructor looked like this:
function Animal(name) {
this.name = name.toLowerCase();
}
You always have to pass a string to Animal, otherwise you will get an error. What will you pass when you do Dog.prototype = new Animal(??);? It doesn't actually matter which string you pass, as long as pass something, which hopefully shows you that this is bad design.
Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
Everything that "adds" the properties from Animal.prototype to Dog.prototype will "work". But the solutions are of different quality. In this case here you will have the problem that any method you add to Dog.prototype will also be added to Animal.prototype.
Example:
Dog.prototype.bark = function() {
alert('bark');
};
Since Dog.prototype === Animal.prototype, all Animal instances have a method bark now, which is certainly not what you want.
Object.create (and even new Animal) add one level of indirection to the inheritance by creating a new object which inherits from Animal.prototype and that new object becomes Dog.prototype.
Inheritance in ES6
ES6 introduces a new syntax to create constructor functions and prototype methods, which looks like this:
class Dog extends Animal {
bark() {
alert('bark');
}
}
This is more convenient than what I explained above, but as it turns out, extends also uses an internal equivalent to Object.create to setup inheritance. See steps 2 and 3 in the ES6 draft.
Which means that using Object.create(SuperClass.prototype) is the "more correct" approach in ES5.
First, running the Animal constructor may have undesired side effects. Consider this:
var Animal = function(name) {
this.name = name;
Animal.instances.push(this);
};
Animal.instances = [];
This version would keep track of all instances that have been created. You don't want your Dog.prototype to be recorded there.
Second, Dog.prototype = Animal.prototype is a bad idea, since that would mean that bark would become a method of Animal.
I'm trying to illustrate the difference a little bit:
Here is what basically happens when you write new Animal():
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype === "object" && Animal.prototype !== null) {
res.__proto__ = Animal.prototype;
}
//calling Animal with the new created object as this
var ret = Animal.apply(res, arguments);
//returning the result of the Animal call if it is an object
if (typeof ret === "object" && ret !== null) {
return ret;
}
//otherise return the new created object
return res;
And here is what basically happens with Object.create:
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype !== "object") {
throw "....";
}
res.__proto__ = Animal.prototype;
//return the new created object
return res;
So it does the same but it doesn't call the Animal function and it also always returns the new created object.
In your case you end up with two different objects. With the first method you get:
Dog.prototype = {
name: undefined,
__proto__: Animal.prototype
};
and with the second method you get:
Dog.prototype = {
__proto__: Animal.prototype
};
You don't really need to have the name property in your prototype, because you already assigning it to your Dog instance with Animal.call(this, 'Dog');.
Your primary goal is to let your Dog instance access all the properties of the Animal prototype, which is achieved by both methods. The first method however does some extra stuff that is not really needed in your case or can even cause unwanted results as Pumbaa80 mentioned.
Let's understand it with code only;
A.prototype = B.prototype;
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = B.prototype;
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//A
console.log(A.prototype);//A {b2: 40}
console.log(B.prototype);//A {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === A); //true
console.log(a.a2);//undefined
A.prototype = Object.create(B.prototype);
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, constructor: function, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//B
console.log(A.prototype);//A {constructor: function, b2: 40}
console.log(B.prototype);//B {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === B); //true
console.log(a.a2);//undefined

prototypical inheritance, new vs prototype? [duplicate]

I've been trying to wrap my head around the new Object.create method which was introduced in ECMAScript 5.
Usually when I want to use inheritance I do something like this:
var Animal = function(name) { this.name = name; }
Animal.prototype.print = function() { console.log(this.name); }
var Dog = function()
{
return Animal.call(this, 'Dog');
}
Dog.prototype = new Animal();
Dog.prototype.bark = function() { console.log('bark'); }
I just assign a newly created Animal object to Dog's prototype and everything works like a charm:
var dog1 = new Dog();
dog1.print(); // prints 'Dog'
dog1.bark(); // prints 'bark'
dog1.name; //prints 'Dog'
but people(without explaining) are saying that Dog.prototype = new Animal(); is not the way inheritance works and that I should use Object.create approach:
Dog.prototype = Object.create(Animal.prototype);
which also works.
What's the benefit of using Object.create or am I missing something?
UPDATE: Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
In the following I assume you are only interested in why Object.create is preferable for setting up inheritance.
To understand the benefits, lets first clarify what a "class" is made of in JavaScript. You have two parts:
The constructor function. This function contains all the logic to create an instance of the "class", i.e. instance specific code.
The prototype object. This is the object the instance inherits from. It contains all methods (and other properties) that should be shared among all instances.
Inheritance establishes an is-a relation, for example, a Dog is an Animal. How is this expressed in terms of constructor function and prototype object?
Obviously a dog must have the same methods as an animal, that is the Dog prototype object must somehow incorporate the methods from the Animal prototype object. There are multiple ways to do this. You will often see this:
Dog.prototype = new Animal();
This works because an Animal instance inherits from the Animal prototype object. But it also implies that every dog inherits from one specific Animal instance. That seems to be a bit strange. Shouldn't instance specific code only be run in the constructor function? Suddenly instance specific code and prototype methods seem to be mixed.
We don't actually want to run Animal instance specific code at that moment, we only want all the methods from the Animal prototype object. That is what Object.create lets us do:
Dog.prototype = Object.create(Animal.prototype);
Here we are not creating a new Animal instance, we only get the prototype methods. The instance specific code is executed exactly where it should be, inside the constructor:
function Dog() {
Animal.call(this, 'Dog');
}
The biggest advantage is that Object.create will always work. Using new Animal() only works if the constructor does not expect any arguments. Imagine if the constructor looked like this:
function Animal(name) {
this.name = name.toLowerCase();
}
You always have to pass a string to Animal, otherwise you will get an error. What will you pass when you do Dog.prototype = new Animal(??);? It doesn't actually matter which string you pass, as long as pass something, which hopefully shows you that this is bad design.
Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
Everything that "adds" the properties from Animal.prototype to Dog.prototype will "work". But the solutions are of different quality. In this case here you will have the problem that any method you add to Dog.prototype will also be added to Animal.prototype.
Example:
Dog.prototype.bark = function() {
alert('bark');
};
Since Dog.prototype === Animal.prototype, all Animal instances have a method bark now, which is certainly not what you want.
Object.create (and even new Animal) add one level of indirection to the inheritance by creating a new object which inherits from Animal.prototype and that new object becomes Dog.prototype.
Inheritance in ES6
ES6 introduces a new syntax to create constructor functions and prototype methods, which looks like this:
class Dog extends Animal {
bark() {
alert('bark');
}
}
This is more convenient than what I explained above, but as it turns out, extends also uses an internal equivalent to Object.create to setup inheritance. See steps 2 and 3 in the ES6 draft.
Which means that using Object.create(SuperClass.prototype) is the "more correct" approach in ES5.
First, running the Animal constructor may have undesired side effects. Consider this:
var Animal = function(name) {
this.name = name;
Animal.instances.push(this);
};
Animal.instances = [];
This version would keep track of all instances that have been created. You don't want your Dog.prototype to be recorded there.
Second, Dog.prototype = Animal.prototype is a bad idea, since that would mean that bark would become a method of Animal.
I'm trying to illustrate the difference a little bit:
Here is what basically happens when you write new Animal():
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype === "object" && Animal.prototype !== null) {
res.__proto__ = Animal.prototype;
}
//calling Animal with the new created object as this
var ret = Animal.apply(res, arguments);
//returning the result of the Animal call if it is an object
if (typeof ret === "object" && ret !== null) {
return ret;
}
//otherise return the new created object
return res;
And here is what basically happens with Object.create:
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype !== "object") {
throw "....";
}
res.__proto__ = Animal.prototype;
//return the new created object
return res;
So it does the same but it doesn't call the Animal function and it also always returns the new created object.
In your case you end up with two different objects. With the first method you get:
Dog.prototype = {
name: undefined,
__proto__: Animal.prototype
};
and with the second method you get:
Dog.prototype = {
__proto__: Animal.prototype
};
You don't really need to have the name property in your prototype, because you already assigning it to your Dog instance with Animal.call(this, 'Dog');.
Your primary goal is to let your Dog instance access all the properties of the Animal prototype, which is achieved by both methods. The first method however does some extra stuff that is not really needed in your case or can even cause unwanted results as Pumbaa80 mentioned.
Let's understand it with code only;
A.prototype = B.prototype;
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = B.prototype;
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//A
console.log(A.prototype);//A {b2: 40}
console.log(B.prototype);//A {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === A); //true
console.log(a.a2);//undefined
A.prototype = Object.create(B.prototype);
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, constructor: function, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//B
console.log(A.prototype);//A {constructor: function, b2: 40}
console.log(B.prototype);//B {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === B); //true
console.log(a.a2);//undefined

Clarifications on prototypal inheritance

I have a prototypal inheritance like below where Student extends Guru. I have three questions, can someone clarify the same.
function Guru(name){
this.name = name;
}
Guru.prototype.copy = function(){
return this.constructor(this.name);
}
function Student(name){
Guru.call(this)
this.name = name;
}
Student.prototype = Object.create(Guru.prototype);
Student.prototype.constructor = Student;
var stu = new Student("John Cena");
console.log(stu.constructor);
console.log(stu.__proto__);
Why should we avoid Student.prototype = new Guru();
What is the difference between these two:
console.log(stu.constructor);
console.log(stu.__proto__);
Prints the below:
[Function: Guru]
Guru { constructor: [Function: Student] }
Difference between constructor.prototype and prototype.constructor? Do we have constructor.prototype in javascript?
Why should we avoid Student.prototype = new Guru()?
Because Guru constructor expects an instance, not a subclass. Properties created in that constructor should be assigned directly to the instance.
In your case it doesn't matter much, but imagine this:
function C1() { this.o = []; }
function C2() {}
C2.prototype = new C1();
var c1a = new C1(), c1b = new C1(),
c2a = new C2(), c2b = new C2();
c1a.o.push(123);
c2a.o.push(456);
c1b.o; // [] -- The property is NOT shared among C1 instances
c2b.o; // [456] -- The property is shared among all Sub instances
What is the difference between stu.constructor and stu.__proto__?
When you create the Student constructor, it receives automatically a prototype with a constructor property which points back to Student.
Instead , __proto__ is a getter which returns the [[Prototype]] of an object. Note this is not much standard (it's only defined in an annex for browsers), you should use Object.getPrototypeOf instead.
Therefore, stu.constructor (inherited from Student.prototype) is Student. And stu.__proto__ (inherited from Object.prototype) is Student.prototype.
Difference between constructor.prototype and prototype.constructor?
Using constructor.prototype on a prototype is pointless because it gives the same prototype (assuming it has not been altered).
Using constructor.prototype on a instance gives the prototype it inherits from (assuming it is not shadowed nor has been altered).
Using prototype.constructor on a constructor is pointless because it gives the same constructor (assuming it has not been altered).

How to use parent and child Constructors in Javascript?

I am trying to understand why and when we use constructors in Javascript.
I was wondering when and how we need to use the constructor of a child and when the parents. Based on my tests there is NO difference when I set the child constructor to itself or to the parent.Lets take a look at the below code :
function Mammal(name) {
this.name = "###"+name;
}
Cat.prototype = new Mammal(); // Here's where the inheritance occurs
Cat.prototype.constructor = Cat; // Otherwise instances of Cat would have a
function Cat(name) {
this.name = name;
}
Now lets instantiate the Cat and Mamal class and see the name:
var mycat = new Cat('Felix');
Alert(mycat.name); //OUTPUT : "Felix"
Now i want to set the constructor of Cat class to the Mamal. To do so I remove the below line
//Cat.prototype.constructor = Cat; -->Now the cat Constructor is set to its default(Mamal)
Now I expect that when I call mycat.name, it uses the Mamal constructor and alert "###Felix"
BUT it doesn't. It shows exactly same as the previous result "Felix".
var mycat = new Cat('Felix');
Alert(mycat.name); //Again OUTPUT is : "Felix" !! but I expected "###Felix"
So, why? And can you give me an example of a correct use of constructors in Javascript and when they are important?
Hopefully an examination of how this code runs should clear things up:
function Mammal(name) {
this.name = "###" + name;
}
function Cat(name) {
this.name = name;
}
Cat.prototype = new Mammal();
// omitted change of Cat.prototype.constructor
var felix = new Cat("Felix");
console.log(felix);
After defining the first two functions, we create a new Mammal, passing it a name of undefined, and putting the result into Cat.prototype. Now Cat.prototype is a Mammal with a name of ###undefined.
Then we create a new Cat, giving the Cat function a name of Felix. This Cat function sets its name property to Felix. The Cat function completes and felix contains a Cat object with a name of Felix.
So why didn’t the Mammal function run? Well, it did, but only once when setting up inheritance. If you want the superclass’s constructor to run as part of the subclass’s initialization, you have to do that explicitly:
function Cat(name) {
Mammal.call(this, name);
this.name = name;
}
Of course, you’d still get the same result, because you’d have the Mammal function set the name property and then Cat would write over it again. You could swap it around, too, so the Mammal overwrites what Cat did:
function Cat(name) {
this.name = name;
Mammal.call(this, name);
}
But then the Cat line of this.name = name; is useless and you might as well remove it.
So why didn’t your constructor change do anything? Because that’s not what constructor does. In fact, reading through the ES5 specification, I didn’t see the constructor property actually being used for anything at all. Changing constructor doesn’t do anything, so that’s why it didn’t matter.

Categories

Resources