I am looking to do some inheritance with JavaScript and while searching the inter-webs I found many examples and multiple ways and implementations of inheritance. I eventually found one that I liked because of it's simplicity and from all the reading and learning I came up with this approach:
var Animal = function () {
var self = this;
self.legs = 4;
self.makeNoise = function () {
return "noise";
};
};
var Dog = function () {
var self = new Animal();
self.base = {
makeNoise: self.makeNoise
};
self.makeNoise = function () {
var noise = "bark \n";
noise += self.base.makeNoise();
return noise;
};
return self;
};
var Monkey = function () {
var self = new Animal();
self.base = {
makeNoise: self.makeNoise
};
self.legs = 2;
self.makeNoise = function () {
var noise = "weird monkey sound \n";
noise += self.base.makeNoise();
return noise;
};
return self;
};
$("#monkey").click(function () {
var monkey = new Monkey();
var result = "Legs: " + monkey.legs + "\n";
result += "Noise: " + monkey.makeNoise();
alert(result);
});
$("#dog").click(function () {
var dog = new Dog();
var result = "Legs: " + dog.legs + "\n";
result += "Noise: " + dog.makeNoise();
alert(result);
});
You can find a working JSFiddle here .
As you can see from the code, I keep a reference of the original base function in a base
variable so I can then call base
. Do you see anything wrong with this approach? Any shortcomings, overseen issues that might arise in the future, anything I'm missing?
Well, here's one thing that's wrong:
var dog = new Dog();
console.log(dog instanceof Dog) //=> false
The problem is, what you're doing is actually not inheritance. You are simply using functions to return a modified version of the animal object. This results in a behavior which is similar to inheritance but isn't the same thing.
JavaScript's object model uses something called the prototype chain, which is very similar to typical object oriented inheritance. The Mozilla Developer Network has a great article on this: Inheritance and the prototype chain .
Here is an example of how you might use prototypical inheritance in your example:
var Animal = function() {};
Animal.prototype = {
legs: 4,
makeNoise: function () {
return "noise";
}
};
var Dog = function () {};
// Notice: Dog.prototype is inheriting from Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.makeNoise = function () {
var noise = "bark \n";
// Notice: calling Animal's makeNoise function with
// 'this' set to our dog object.
noise += Animal.prototype.makeNoise.call(this);
return noise;
};
var Monkey = function () {};
// Notice: Monkey.prototype is inheriting from Animal.prototype
Monkey.prototype = Object.create(Animal.prototype)
Monkey.prototype.legs = 2;
Monkey.prototype.makeNoise = function () {
var noise = "weird monkey sound \n";
// Notice: calling Animal's makeNoise function with
// 'this' set to our monkey object.
noise += Animal.prototype.makeNoise.call(this);
return noise;
};
$("#monkey").click(function () {
var monkey = new Monkey();
var result = "Legs: " + monkey.legs + "\n";
result += "Noise: " + monkey.makeNoise();
alert(result);
});
$("#dog").click(function () {
var dog = new Dog();
var result = "Legs: " + dog.legs + "\n";
result += "Noise: " + dog.makeNoise();
alert(result);
});
$("#inheritance").click(function () {
var dog = new Dog();
var monkey = new Monkey();
var result = 'dog instanceof Dog = ' + (dog instanceof Dog) + "\n" +
'dog instanceof Animal = ' + (dog instanceof Animal) + "\n" +
'dog instanceof Monkey = ' + (dog instanceof Monkey) + "\n" +
'monkey instanceof Monkey = ' + (monkey instanceof Monkey) + "\n" +
'monkey instanceof Animal = ' + (monkey instanceof Animal) + "\n" +
'monkey instanceof Dog = ' + (monkey instanceof Dog) + "\n";
alert(result);
});
Besides that by returning self
breaks the inheritance chain, you may have a misunderstanding with JavaScript's inheritance technique:
JavaScript is a prototypal-based language, meaning proper inheritance is set up as so:
function Animal(){}
Animal.prototype.walk = function(){
console.log('walking...');
};
Animal.prototype.roar = function(){
alert('roar');
};
function Dog(){}
Dog.prototype = new Animal();
Dog.prototype.roar = function(){
alert('bark!');
};
var animal = new Animal();
var dog = new Dog();
animal.walk();
dog.walk(); // both can call the walk function
animal.roar(); // alerts roar
dog.roar(); // alerts bark
Prototypal inheritance allows shared memory of the object definition (log an object to your console to see what I mean). In other words, every instance of Dog
is going to use that same roar
function, but by attaching attributes directly to this
in the constructor, you're preventing the prototype chain and delegating the memory for the function to every instance of that object. If you're going to create many instances of that object, the performance of the app will reflect this.
@Thom is demonstrating classical inheritance vs. prototypal as in my examples. Either is right, but here is a good Stack answer about this .
This is an excellent article: http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/
//Constructor/Object
function Animal(inNoise) {
this.legs = 4;
this.noise = inNoise;
}
//Set Objects prototypes
Animal.prototype = {
constructor: Animal,
changeNoise: function(newNoise){this.noise = newNoise;}
}
//Create some dogs
var dog = new Animal('bark');
var pitbull = Object.create(dog);
var chiahua = Object.create(dog);
//Change dogs noise
chiahua.changeNoise('littleBark');
alert(dog.noise); //bark
alert(pitbull.noise);//bark
alert(chiahua.noise); //littlebark
alert(chiahua.legs); //4
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.