Object Oriented Javascript is not an easy concept to grasp, the language implements object oriented programming(oop) concepts via the Prototypical Model, it’s a powerful model that allows JS to be an extremely flexible language. In this article I will explain to you that concept and help you unlock the power of OOP javascript.
Let’s take a look at the following Class definition:
// We usually capitalize class names
var Person= function(name) {
this.name = name; // public variable
this._health = 100; // private variable
console.log('Person constructor called');
// class method
this.walk= function() {
console.log(this.name + ' is walking')
}
// getter
this.getHealth = function() {
return this._health;
}
// setter
this.setHealth = function(health) {
this._health = health;
}
}
This code above is how we can define a Person class with some class variables and methods.
We set two class variables with:
this.name = name;
this._health = 100;
then we specified a getter method called getHealth:
this.getHealth = function() {
return this._health;
}
and a setter method called setHealth:
this.setHealth = function(health) {
this._health = health;
}
and finally we instantiate two Person instances: joe and alice:
// Create some new persons, note, the `new` keyword is used to invoke a constructor
var joe = new Person('joe');
joe.setHealth(100);
console.log(joe.getHealth()); // 100
joe.walk(); // joe is walking
var alice = new Person('alice');
alice.setHealth(30);
console.log(alice.getHealth()); // 30
alice.walk(); // alice is walking
Let’s create a common method for the Person class so all instances of it can immediate access it:
Person.prototype.sleep= function() {
console.log(this.name + ' is sleeping');
}
joe.sleep(); // joe is sleeping
alice.sleep(); // alice is sleeping
Pretty simple right? The syntax for OOP in javascript is a bit difference than languages like Java, C++ or Python. There is no public, private, static keywords in javascript, but the these features can be emulated via the concept of closure.
Inheritance
You can use inheritance as a way to create new classes based on an existing parent class, this newly created child class will inherit all properties and methods of the parent class.
Let’s create a class call Criminal that inherits from Person:
// Inheritance
var Criminal = function(name, crime) {
Person.call(this, name);
this.crime = 'bank robber';
console.log('Criminal constructor called');
}
Criminal.prototype = Object.create(Person.prototype);
Criminal.prototype.constructor = Criminal;
we use Person.call(this, name) to call the constructor of the parent’s class, Person.
We then use
Criminal.prototype = Object.create(Person.prototype);
Criminal.prototype.constructor = Criminal;
to create a Criminal class that inherits from Person class and set Criminal’s constructor to itself.
Method Override (Polymorphism)
If you want to override a parent class’s method, you can do so like this:
// Method override
Criminal.prototype.sleep= function(arg) {
console.log('Criminals don\'t sleep! They rob banks!');
}
and if you want to add a method to Criminal class only:
// Add a method ONLY to criminal class
Criminal.prototype.robBank = function() {
console.log('Criminal is robbing a bank');
}
Encapsulation
The concept of encapsulation is enforced because the Criminal class can use the parent class’s walk() method without needing to know how it was implemented.
Polymorphism is achived by allowing the child class to override the parent’s method, as we saw from the Criminal class’s sleep() method.
Private Variables
We can achieve pseudo private variables by enforcing the usage of getters/setters for our private variables (usually denoted by an underscore _ before the variable name, in our example, the variable _health is private.
Prototype Chain
Javascript will internally keep track of which methods belong to which classes through the concept of prototype chain. The idea is simple, when you ask an instance to invoke a method, it will look for that method in the current Class’s definition, if it finds it then it will invoke it otherwise it will look at the parent class of the instance and see if that method exists there, and invoke it if found, repeat this rule until you reach the base Object class (all classes inherit from this base object).
You can test this out by opening up your browser console, and type in
Array.prototype
you can see a list of functions defined to the Array object, and if you look at the very last property: __proto__, this property tells you who the parent class the Array object is inherited from, in this case, it’s the native Object.
A good standard of practice is to only modify the prototype of your own classes, never modify prototypes of standard Javascript objects (Math, Date, String, Array), so you don’t unintentionally break functionalities when you use third party libraries who rely on the standard javascript objects.
Let’s put this together and see what’s going on:
// Create a Criminal instance
var bob = new Criminal('bob');
bob.sleep(); // this method was overridden, prints out "Criminals don't sleep! They rob banks!"
bob.robBank(); // special method only for Criminal class, prints out "Criminal is robbing a bank"
joe.robBank(); // Error, this method does not exist on Person class, it only exists in Criminal class
here’s an UML diagram of the classes and their relationships
Conclusion
I hope this tutorial cleared up some confusions about prototypical inheritance in Javascript, it’s not as simple the first few times you look at it, but hopefully it’ll make sense the more you read about it.
Here are some resources you might want to check out to further explain this subject:
- Introduction to Object-Oriented JavaScript
- Why is it necessary to set the prototype constructor?
- Classical Inheritance in JavaScript
- Common Misconceptions About Inheritance in JavaScript
If you enjoyed this tutorial, make sure to subscribe to our Youtube Channel and follow us on Twitter @pentacodevids for latest updates!