I have a base class:
function Monster() {
this.health = 100;
}
Monster.prototype.growl = function() {
console.log(\"Grr!\");
}
That
I can propose one variant, just have read in book, it seems the simplest:
function Parent() {
this.name = 'default name';
};
function Child() {
this.address = '11 street';
};
Child.prototype = new Parent(); // child class inherits from Parent
Child.prototype.constructor = Child; // constructor alignment
var a = new Child();
console.log(a.name); // "default name" trying to reach property of inherited class
Updated below for ES6
This MDN document describes extending classes well:
https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
In particular, here is now they handle it:
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);
}
// inherit Person
Student.prototype = Object.create(Person.prototype);
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Note that Object.create() is unsupported in some older browsers, including IE8:
If you are in the position of needing to support these, the linked MDN document suggests using a polyfill, or the following approximation:
function createObject(proto) {
function ctor() { }
ctor.prototype = proto;
return new ctor();
}
Using this like Student.prototype = createObject(Person.prototype)
is preferable to using new Person()
in that it avoids calling the parent's constructor function when inheriting the prototype, and only calls the parent constructor when the inheritor's constructor is being called.
Thankfully, the JavaScript designers have heard our pleas for help and have adopted a more suitable way of approaching this issue.
MDN has another great example on ES6 class inheritance, but I'll show the exact same set of classes as above reproduced in ES6:
class Person {
sayHello() {
alert('hello');
}
walk() {
alert('I am walking!');
}
}
class Student extends Person {
sayGoodBye() {
alert('goodBye');
}
sayHello() {
alert('hi, I am a student');
}
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Clean and understandable, just like we all want. Keep in mind, that while ES6 is pretty common, it's not supported everywhere:
For traditional extending you can simply write superclass as constructor function, and then apply this constructor for your inherited class.
function AbstractClass() {
this.superclass_method = function(message) {
// do something
};
}
function Child() {
AbstractClass.apply(this);
// Now Child will have superclass_method()
}
Example on angularjs:
http://plnkr.co/edit/eFixlsgF3nJ1LeWUJKsd?p=preview
app.service('noisyThing',
['notify',function(notify){
this._constructor = function() {
this.scream = function(message) {
message = message + " by " + this.get_mouth();
notify(message);
console.log(message);
};
this.get_mouth = function(){
return 'abstract mouth';
}
}
}])
.service('cat',
['noisyThing', function(noisyThing){
noisyThing._constructor.apply(this)
this.meow = function() {
this.scream('meooooow');
}
this.get_mouth = function(){
return 'fluffy mouth';
}
}])
.service('bird',
['noisyThing', function(noisyThing){
noisyThing._constructor.apply(this)
this.twit = function() {
this.scream('fuuuuuuck');
}
}])
There are multiple ways which can solve the problem of extending a constructor function with a prototype in Javascript. Which of these methods is the 'best' solution is opinion based. However, here are two frequently used methods in order to extend a constructor's function prototype.
class Monster {
constructor(health) {
this.health = health
}
growl () {
console.log("Grr!");
}
}
class Monkey extends Monster {
constructor (health) {
super(health) // call super to execute the constructor function of Monster
this.bananaCount = 5;
}
}
const monkey = new Monkey(50);
console.log(typeof Monster);
console.log(monkey);
The above approach of using ES 2015
classes is nothing more than syntactic sugar over the prototypal inheritance pattern in javascript. Here the first log where we evaluate typeof Monster
we can observe that this is function. This is because classes are just constructor functions under the hood. Nonetheless you may like this way of implementing prototypal inheritance and definitively should learn it. It is used in major frameworks such as ReactJS
and Angular2+
.
Object.create()
:function makeMonkey (bananaCount) {
// here we define the prototype
const Monster = {
health: 100,
growl: function() {
console.log("Grr!");}
}
const monkey = Object.create(Monster);
monkey.bananaCount = bananaCount;
return monkey;
}
const chimp = makeMonkey(30);
chimp.growl();
console.log(chimp.bananaCount);
This method uses the Object.create()
method which takes an object which will be the prototype of the newly created object it returns. Therefore we first create the prototype object in this function and then call Object.create()
which returns an empty object with the __proto__
property set to the Monster object. After this we can initialize all the properties of the object, in this example we assign the bananacount to the newly created object.