简体   繁体   中英

Javascript Inheritance ; call and prototype

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 .

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

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');

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
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM