Inheritance and Super in JavaScript
What is the constructor and super() keyword. I believe it is for inheritance?
That's right. The above sets up class B
and then has class A
subclass it. The constructor
is the function called when you create a new instance of the class, as in the let c = new A("Testing", "37");
line in the code. Unlike some other languages, in JavaScript there can only be one constructor for a class.
super
is used in subclasses to refer to the superclass. In a constructor, you call super
as though it were a function, and that calls the superclass's constructor function, giving it a chance to do its initialization of the new object that was created by new
. So for instance, in A
's constructor
, super()
calls B
's constructor
.
You can also use super
as the source of a property accessor expression to access properties (including methods) on the superclass. That's what's happening in A
's printName
method, where it uses super.printName()
to call B
's printName
method. (Which will fail, because B
doesn't have a printName
method; B
's method is called printn
.)
I'd be remiss if I didn't point out that although this looks a lot like the class-based OOP in, say, Java or C#, it isn't. It's syntactic sugar (the good kind of sugar) for setting up JavaScript's normal prototypical inheritance using constructor functions. It hugely simplifies setting up prototypical inheritance hierarchies using constructor functions. I'd also be remiss if I didn't point out that using constructor functions to do prototypical inheritance is not necessary, you can do prototypical inheritance without using constructor functions via Object.create
.
There's a lot more to explore. MDN is probably a good starting point.
I can't get this code to work.
The C
in Console.log
shouldn't be capitalized, so change
Console.log(c.printn());
to
console.log(c.printn());
Other than that, if you're using a JavaScript engine that supports class
(such as the one in Google Chrome or Mozilla Firefox), that code works fine although note again that A
seems to expect B
to have a printName
method, but it doesn't, and the code at the end is calling printn
which only B
has (which is fine, it just means A
's code isn't really involved).
class B { constructor(name) { this.name = name; }
printn() { return this.name; }}
class A extends B { constructor(name, age) { super(name); this._age = age; }
get age() { return this._age; }
printName(){ return super.printName(); }}
let c = new A("Testing", "37");console.log(c.printn());
ES6 Class Multiple inheritance
An object can only have one prototype. Inheriting from two classes can be done by creating a parent object as a combination of two parent prototypes.
The syntax for subclassing makes it possible to do that in the declaration, since the right-hand side of the extends
clause can be any expression. Thus, you can write a function that combines prototypes according to whatever criteria you like, and call that function in the class declaration.
How to inherit from a class in javascript?
I have changed how I do this now, I try to avoid using constructor functions and their prototype
property, but my old answer from 2010 is still at the bottom. I now prefer Object.create()
. Object.create
is available in all modern browsers.
I should note that Object.create
is usually much slower than using new
with a function constructor.
//The prototype is just an object when you use `Object.create()`
var Base = {};
//This is how you create an instance:
var baseInstance = Object.create(Base);
//If you want to inherit from "Base":
var subInstance = Object.create(Object.create(Base));
//Detect if subInstance is an instance of Base:
console.log(Base.isPrototypeOf(subInstance)); //True
jsfiddle
One of the big benefits of using Object.create is being able to pass in a defineProperties argument, which gives you significant control over how properties on the class can be accessed and enumerated over, and I also use functions to create instances, these serve as constructors in a way, as you can do initialization at the end instead of just returning the instance.
var Base = {};
function createBase() {
return Object.create(Base, {
doSomething: {
value: function () {
console.log("Doing something");
},
},
});
}
var Sub = createBase();
function createSub() {
return Object.create(Sub, {
doSomethingElse: {
value: function () {
console.log("Doing something else");
},
},
});
}
var subInstance = createSub();
subInstance.doSomething(); //Logs "Doing something"
subInstance.doSomethingElse(); //Logs "Doing something else"
console.log(Base.isPrototypeOf(subInstance)); //Logs "true"
console.log(Sub.isPrototypeOf(subInstance)); //Logs "true
jsfiddle
This is my original answer from 2010:
function Base ( ) {
this.color = "blue";
}
function Sub ( ) {
}
Sub.prototype = new Base( );
Sub.prototype.showColor = function ( ) {
console.log( this.color );
}
var instance = new Sub ( );
instance.showColor( ); //"blue"
Performing inheritance in JavaScript
The JavaScript object oriented paradigm is prototype based. There are no "classes", just objects.
You can implement inheritance in different ways. The two more popular alternatives are the "pseudo-classical" and the "prototypal" forms. For example:
Pseudo-classical inheritance
I think this is the most popular way. You create constructor functions that you use with the new operator, and you add members through the constructor function prototype.
// Define the Person constructor function
function Person() {}
Person.prototype.sayHello = function(){
alert ('hello');
};
// Define the Student constructor function
function Student() {}
// Inherit from Person
Student.prototype = new Person();
// Correct the constructor pointer, because it points to Person
Student.prototype.constructor = Student;
// Replace the sayHello method (a polymorphism example)
Student.prototype.sayHello = function () {
alert('hi, I am a student');
}
var student1 = new Student();
student1.sayHello();
Prototypal inheritance
Basically we make a helper function that takes an object as a parameter and returns an empty new object that inherits from the old one, objects inherit from objects.
// Helper function
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
var person = {
sayHello : function () {
alert('Person object');
},
walk : function () {
alert('walk');
}
};
var student1 = Object.create(person);
student1.sayHello = function () {
alert('hello I am a student');
};
Another interesting form is the parasitic inheritance. In the "derived" constructor you create a "base" object instance. That object is augmented and that new instance is returned:
// Person constructor function
function Person(name) {
this.name = name;
}
function Student(value) {
var that = new Person(value);
that.sayHello = function () {
alert('hello I am a student');
};
return that;
}
JavaScript inheritance not working as I expected
By doing this later in your code
PermanentEmployee.prototype = employee;
you might override this
PermanentEmployee.prototype.getSalary = function()
Try this instead:
function Employee(name) { this.name = name;}
Employee.prototype.getName = function() { return this.name;} function PermanentEmployee(name, annualSalary) { Employee.call(this, name); // calling parent's "constructor" this.annualSalary = annualSalary;}PermanentEmployee.prototype = Object.create(Employee.prototype); // setting "inheritance"PermanentEmployee.prototype.getSalary = function() { return this.annualSalary;}var pe = new PermanentEmployee("Mark", 5000);
console.log(pe.getName());console.log(pe.getSalary());
Javascript Inheritance Explanation
Last two console logs give you true
because
speedBoat
instance is created fromSpeedBoat
class =>speedBoat = new SpeedBoat()
- Similarly,
boat
instance is created fromBoat
class =>boat = new Boat()
The fist one gives you false
because
yatch
instance is created from Yatch
class => yatch = new Yatch()
and you're checking if this yatch
instance is an instance of Boat
class which is NOT TRUE
Why inheritance is not working for you when you do - console.log(yatch instanceof Boat)
- Inheritance is the concept where Child class (Yatch in this case) is getting all its properties and methods from the parent class Boat. But that's not happening in your case as you're not inheriting it properly.
- In your
Yatch
classes' constructor (and all other constructors), you're defining like this:
The below code doesn't work
class Yatch {
constructor() {
new Boat() // this line is creating object/instance of Boat class and this object is not pointing to any variable and hence will be garbage collected (will be removed from the memory)
}
}
How to define inheritance?
You need to use extends keyword in the Child class (Yatch) and tell which should be the parent class (Boat) like this
class Yatch extends Boat{
super() { // this super keyword calls the constructor of parent (Boat class)
new Boat()
}
}
Modified working code - https://codepen.io/sandeep194920-the-flexboxer/pen/bGvaoyW?editors=1111
JavaScript: Object inheriting from Function.prototype
TL;DR
Object.prototype is last in the prototype chain and it doesn't inherit from anything. The Object constructor is the one that inherits from Function.prototype because it's just a function; it's a Function instance.
Long Version
Since your question is a general one, I'll try to describe a few subjects and hopefully you will answer your own question. Here are the subjects I'll try to cover:
- Two ways to use the word "prototype".
- How classes are created in JavaScript.
- How the Function & Object constructors relate.
Note: It can be hard and at times confusing to explain how JavaScript really works. I hope that you'll get something out of it though.
Two ways to use the word "prototype"
The word "prototype" can be a little confusing in JavaScript. That's because there are at least two ways to use this word depending on the context:
1) "The prototype object of another object"
The prototype object of another object is also talked about as the "internal prototype", denoted as [[Prototype]], or __proto__
; they all mean the same thing. As an example let's take this array: nums = [9, 8, 7];
. We say that nums
is an array... but why?
- We say it's an array because it is an instance of the
Array
constructor (constructors are just functions, except we use them with the new keyword). - We also say it's an array because its prototype object (a.k.a. "internal prototype") is the object contained inside of the
Array.prototype
property.
2) "The prototype property of a constructor function"
Continuing with the nums
array example, the Array constructor function has a property named prototype
, and we can access it like this: Array.prototype
. This property is the "internal prototype" of Array instances, and provides all the methods that we're used to calling on arrays - e.g. forEach
, push
, pop
, join
, and so on.
So, along the same lines, the internal prototype of my function foo()
, or any other function, is the object that's contained inside of the Function.prototype
property; in other words, Function.prototype
is any function's "internal prototype" object. Also, we can say that the Function constructor has a prototype property, which eventually is the "internal prototype" of all functions.
Where I'm getting at is that we speak of one thing (the prototype) in two different ways. In the first way we say: "the prototype/internal prototype" of an object, and in the second way we say: "the constructor's prototype" property.
How classes are created in JavaScript
In JavaScript constructor functions are like classes in other programming languages. Well, not quite. Actually, to resemble classes, JavaScript uses a combination of a constructor function and another object called the prototype. Actually every JavaScript function acquires a prototype property automatically because a function can be used as a constructor or simply as a function. When a function isn't used as a constructor, its prototype property isn't used for anything and it's just dangling there as a useless property.
In classical languages, the class contains both the instance variables and the instance methods, however in JavaScript, the constructor function contains the instance variables and its prototype object contains the instance methods.
Instance variables are unique to the particular instance of a constructor function (they contain instance specific data), and instance methods are shared by all instances. In other words, all instances can execute the instance methods but cannot access the variables of each other.
So, all objects in JavaScript are instances of their respective constructor functions. For example, an array such as [1,2,3]
is an instance of the function Array() {}
constructor. Objects such as {key: 'value'}
are instances of the function Object() {}
constructor. JavaScript functions such as alert()
are instances of the function Function() {}
constructor... and so on.
Again, all constructor functions in JavaScript have a prototype
property, and this property includes the methods that instances of the constructor will inherit.
Example:
// Person constructor to create people instances
function Person(name, age) {
// Every instance has its own "instance variables", a.k.a. properties.
this.name = name;
this.age = age;
}
// The "instance methods"
Person.prototype = {
greet: function() {
return 'Hello ' + this.name;
},
//...
};
// Joe is an instance of the `Person` constructor, and Joe's "prototype"
// is the `Person.prototype` object. We call Joe's "prototype" the
// "internal prototype".
var joe = new Person('Joe Doe', 44);
joe.name; //=> Joe Doe
joe.greet(); //=> Hello Joe Doe
How the Function & Object constructors relate
The Object
Constructor.
The Object constructor is just like the Person constructor above, except it creates object instances instead of person instances.
The Function
Constructor.
The Function constructor is just like the Person & Object constructors above, except that it creates Function instances, in other words it creates functions.
All constructors in JavaScript like Person
, Object
, Array
, Function
, String
, Boolean
, and so on, are just functions. Since they are functions, it means that they were created with new Function
internally in the language, and all function methods like call()
and apply()
come from Function.prototype. In other words, Function.prototype is the "prototype/internal prototype" object of all functions, including constructors and the function Function
itself.
Conclusion:
Don't confuse a constructor's prototype
property, which includes the methods that future instances will use, with the internal prototype of the constructor itself.
However, keep in mind that a constructor's prototype
property is the internal [[Prototype]] of that constructor's instances. For example, Function.prototype
is the internal [[Prototype]] for the Object
constructor, and that makes sense since the Object
constructor is just another function (a Function
instance).
For a code conclusion take a look at how the Object & Function constructors are created internally in JavaScript:
// Object constructor
// ==============================================
function Object() { /* ... */ }
// Object.keys()
// Object.observe()
// ...
// `Object.__proto__` (internal [[Prototype]])
// -----------------------------------------------
// Since `Object` is a function, it inherits all of Function's
// instance methods (the ones inside of Function.prototype).
//
// In other words the `Object` constructor can use methods
// like `apply()`, `call()`, `bind()`, and more.
//
// So we can say that the Object's prototype is the
// `Function.prototype` object.
Object.__proto__ = Function.prototype;
// `Object.prototype` (instance methods)
// -----------------------------------------------
// The Object's `prototype` property is totally different from
// the `__proto__` property. This `prototype` property includes
// methods that all JavaScript objects inherit. So an object
// literal like `var obj = {}` or an array like `var arr = []`
// or even a function like `alert` can use these methods.
Object.prototype = {
constructor: Object,
hasOwnProperty: function() {},
isPrototypeOf: function() {},
//...
};
// Function constructor
// ==============================================
function Function() { /* ... */ }
// Function.call()
// Function.apply()
// ...
// [[Prototype]] + instance methods
// -----------------------------------------------
// Since `Function` is a function itself and at the same time
// the constructor for other JavaScript functions, its internal
// [[Prototype]] and the `prototype` property point to the same
// exact object.
Function.__proto__ = Function.prototype = {
apply: function() {},
call: function() {},
bind: function() {},
//...
// Just an object literal, so it inherits the
// Object's instance methods.
__proto__: Object.prototype
};
Further Resources
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Determining_instance_relationships
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
- https://es5.github.io/#x15.3.4
- http://people.mozilla.org/~jorendorff/es5.1-final.html#sec-15.3.2.1; A prototype property is automatically created for every function, to provide for the possibility that the function will be used as a constructor.
- https://www.quora.com/In-JavaScript-what-is-the-logic-behind-the-data-structure-of-function-prototype-proto-and-constructor?share=1
Prototypical inheritance - writing up
Constructor function introduction
You can use a function as a constructor to create objects, if the constructor function is named Person then the object(s) created with that constructor are instances of Person.
var Person = function(name){
this.name = name;
};
Person.prototype.walk=function(){
this.step().step().step();
};
var bob = new Person("Bob");
Person is the constructor function. When you create an instance using Person you have to use the new keyword:
var bob = new Person("Bob");console.log(bob.name);//=Bob
var ben = new Person("Ben");console.log(ben.name);//=Ben
The property/member name
is instance specific, it's different for bob and ben
The member walk
is part of Person.prototype and is shared for all instances bob and ben are instances of Person so they share the walk member (bob.walk===ben.walk).
bob.walk();ben.walk();
Because walk() could not be found on bob directly JavaScript will look for it in the Person.prototype as this is the constructor of bob. If it can't be found there it'll look on Object.prototype. This is called the prototype chain. The prototype part of inheritance is done by lengthening this chain; for example bob => Employee.prototype => Person.prototype => Object.prototype (more on inheritance later).
Even though bob, ben and all other created Person instances share walk the function will behave differently per instance because in the walk function it uses this
. The value of this
will be the invoking object; for now let's say it's the current instance so for bob.walk()
"this" will be bob. (more on "this" and the invoking object later).
If ben was waiting for a red light and and bob was at a green light; then you'll invoke walk() on both ben and bob obviously something different would happen to ben and bob.
Shadowing members happens when we do something like ben.walk=22
, even though bob and ben share walk
the assignment of 22 to ben.walk will not affect bob.walk. This is because that statement will create a member called walk
on ben directly and assign it a value of 22. There will be 2 different walk members: ben.walk and Person.prototype.walk.
When asking for bob.walk you'll get the Person.prototype.walk function because walk
could not be found on bob. Asking for ben.walk however will get you the value 22 because the member walk has been created on ben and since JavaScript found walk on ben it will not look in the Person.prototype.
When using Object.create with 2 arguments, Object.defineProperty or Object.defineProperties shadowing works a bit different. More info on that here.
More about prototype
An object can inherit from another object through the use of prototype. You can set the prototype of any object with any other object using Object.create
. In the constructor function introduction we have seen that if a member can't be found on the object then JavaScript will look in the prototpe chain for it.
In previous part we have seen that re assignment of members that come from an instance's prototype (ben.walk) will shadow that member (create walk on ben rather than changing Person.prototype.walk).
What if we don't re assign but mutate the member? Mutating is (for example) changing sub properties of an Object or invoking functions that will change the object's value. For example:
var o = [];
var a = o;
a.push(11);//mutate a, this will change o
a[1]=22;//mutate a, this will change o
The following code demonstrates the difference between prototype members and instance members by mutating members.
var person = {
name:"default",//immutable so can be used as default
sayName:function(){
console.log("Hello, I am "+this.name);
},
food:[]//not immutable, should be instance specific
// not suitable as prototype member
};
var ben = Object.create(person);
ben.name = "Ben";
var bob = Object.create(person);
console.log(bob.name);//=default, setting ben.name shadowed the member
// so bob.name is actually person.name
ben.food.push("Hamburger");
console.log(bob.food);//=["Hamburger"], mutating a shared member on the
// prototype affects all instances as it changes person.food
console.log(person.food);//=["Hamburger"]
The code above shows that ben and bob share members from person. There is only one person, it is set as bob's and ben's prototype (person is used as the first object in the prototype chain to look up requested members that don't exist on the instance). The problem with the above code is that bob and ben should have their own food
member. This is where the constructor function comes in. It is used to create instance specific members. You could also pass arguments to it to set values of these instance specific members.
The next code shows another way to implement the constructor function, syntax is different but the idea is the same:
- Define an object that has members that will be same for many instances (person is a blueprint for bob and ben and can be for jilly, marie, clair ...)
- Define instance specific members that should be unique for instances (bob and ben).
- Create an instance running the code in step 2.
With constructor functions you'll set the prototype in step 2 in the following code we set the prototype in step 3.
In this code I have removed name from prototype as well as food because you are most likely going to shadow this almost immediately when creating an instance anyway. Name is now an instance specific member with a default value set in the constructor function. Becaus the food member is also moved from prototype to instance specific member it will not affect bob.food when adding food to ben.
var person = {
sayName:function(){
console.log("Hello, I am "+this.name);
},
//need to run the constructor function when creating
// an instance to make sure the instance has
// instance specific members
constructor:function(name){
this.name = name || "default";
this.food = [];
return this;
}
};
var ben = Object.create(person).constructor("Ben");
var bob = Object.create(person).constructor("Bob");
console.log(bob.name);//="Bob"
ben.food.push("Hamburger");
console.log(bob.food);//=[]
You may come across similar patterns that are more robust to help with object creation and object definition.
Inheritance
The following code shows how to inherit. The tasks are basically the same as in code before with a little extra
- Define instance specific members of an object (functions Hamster and RussionMini).
- Set the prototype part of inheritance (RussionMini.prototype = Object.create(Hamster.prototype))
- Define members that can be shared among instances.(Hamster.prototype and RussionMini.prototype)
- Create an instance running the code in step 1 and for objects that inherit have them run the Parent code as well (Hamster.apply(this,arguments);)
Using a pattern some would call "classical inheritance". If you are confused by the syntax I'll be happy to explain more or provide different patterns.
function Hamster(){
this.food=[];
}
function RussionMini(){
//Hamster.apply(this,arguments) executes every line of code
//in the Hamster body where the value of "this" is
//the to be created RussionMini (once for mini and once for betty)
Hamster.apply(this,arguments);
}
//setting RussionMini's prototype
RussionMini.prototype=Object.create(Hamster.prototype);
//setting the built in member called constructor to point
// to the right function (previous line has it point to Hamster)
RussionMini.prototype.constructor=RussionMini;
mini=new RussionMini();
//this.food (instance specic to mini)
// comes from running the Hamster code
// with Hamster.apply(this,arguments);
mini.food.push("mini's food");
//adding behavior specific to Hamster that will still be
// inherited by RussionMini because RussionMini.prototype's prototype
// is Hamster.prototype
Hamster.prototype.runWheel=function(){console.log("I'm running")};
mini.runWheel();//=I'm running
Object.create to set prototype part of inheritance
Here is the documentation about Object.create, it basically returns the second argument (not supported in the polyfil) with the first argument as the returned object's prototype.
If no second argument was given it'll return an empty object with first argument to be used as the returned object's prototype (the first object to be used in the returned object's prototype chain).
Some would set the prototype of RussionMini to an instance of Hamster (RussionMini.prototype = new Hamster()). This is not desirable because even though it accomplishes the same (RussionMini.prototype's prototype is Hamster.prototype) it also sets Hamster instance members as members of RussionMini.prototype. So RussionMini.prototype.food will exist but is a shared member (remember bob and ben in "More about prototype"?). The food member will be shadowed when creating a RussionMini because Hamster code is run with Hamster.apply(this,arguments);
that in turn runs this.food = []
but any Hamster members will still be members of RussionMini.prototype.
Another reason could be that to create a Hamster a lot of complicated calculations need be done on passed arguments that may be not available yet, again you could pass in dummy arguments but it could unnecessarily complicate your code.
Extending and overriding Parent functions
Sometimes children
need to extend parent
functions.
You want the 'child' (=RussionMini) to do something extra. When RussionMini can call the Hamster code to do something and then do something extra you don't need to copy and paste Hamster code to RussionMini.
Related Topics
Get First and Last Date of Current Month with JavaScript or Jquery
Making Custom Right-Click Context Menus for My Web-App
What's the Best Way to Break from Nested Loops in JavaScript
Merge Multiple Objects Inside the Same Array into One Object
Detecting iOS/Android Operating System
Need to Escape a Special Character in a Jquery Selector String
Multiple Left-Hand Assignment with JavaScript
Sorting in JavaScript: Should Every Compare Function Have a "Return 0" Statement
Checking If Jquery Is Loaded Using JavaScript
Map and Filter an Array at the Same Time
Difference Between JSON.Stringify and JSON.Parse
Download and Open PDF File Using Ajax
JavaScript Drag and Drop for Touch Devices
Javascript: Formatting a Rounded Number to N Decimals