Inheritance and encapsulation is an essential tennant of OOP. JS does things a little bit differently than most languages, we’ll go over those differences in this post. It’s assumed you already have a basic familiarty w/ OO JS, if not head over my OO JS in 15mins or Less tutorial to cover the basics.
JavaScript technically doesn’t have classes but it does have constructors. Constructors act as containers for class variables and methods just like the class statement in other languages. Let’s start by creating a constructor function.
function Person() {};
Looks good, to bad it’s empty. Let’s tack on an instance variable and a method that can access that instance variable w/ prototype (Need a crash course on prototype in JS? See the posts by Yehuda Katz or Angus Croll).
Person.prototype.type = "Human";
Person.prototype.sayType = function() {
console.log("Type: " this.type);
}
var me = new Person();
me.sayType(); // "Type: Human"
Beautiful. So we’ve created a class, well technically it’s not a class, but for simplicity sake we’ll call it a class. Next let’s create a child class called SuperHero that extends our Person class. This means it will have all the properties, and methods available to instances of the Person class.
function SuperHero() {}; // New class
SuperHero.prototype = new Person(); // Inherit from Person
var bo = new SuperHero();
bo.type = "Super Hero";
bo.sayType; // "Super Hero"
Awesome! Our SuperHero class is a child of the Person class. It inherited the type property of the Person class which defaults to “Human”, and the sayType method of the Person class too. This is referred to as behaviour reuse, in a class based language it would be call inheritance.
How about we add an instance variable to our child class. The instance variable will only be available to the child class.
SuperHero.prototype.power = "X-Ray vision";
bo.power; // "X-Ray vision"
me.power; // Undefined, humans don't have powers silly
We can add a method to our parent class, and it will be available to our child class.
Person.prototype.walk = function() {
console.log("Walking");
}
me.walk(); // "Walking"
bo.walk(); // "Walking", woo it's available to both child and parent
Next let’s look at creating private methods and properties now.
function Game() {
// Private property
var title;
// Private method, only available w/ in our class
function get_title() {
return title;
}
// Private method, only available w/ in our class
function set_title(newTitle) {
title = newTitle;
}
this.getTitle = function() {
return title;
};
this.setTitle = function(newTitle) {
title = newTitle;
};
}
Ok looks good, we created a Game class w/ the the private property title. To change the value of title the user of our class will call the public method setTitle which in turn calls the private method setTitle. Likewise to call title the user of our class calls a public method getTitle which in turn calls the private method get_title.
Using this pattern gives the creator of the class the ability to control the value of title (our data), and it forces all changes to title to go through a specific channel. Let’s see this process in action.
var sor = new Game();
sor.setTitle("Streets of Rage");
sor.title; // Undefined, we can't access it directly
sor.getTitle(); // "Streets of Rage", woo hoo it works!
Awesome, let’s add a public property called console to our game class.
Game.prototype.console = "SNES";
sor.console = "Sega";
sor.console; // "Sega", ok so far so good
How about a method that can access the console property too.
Game.prototype.sayConsole = function() {
console.log("Console: " + this.console);
}
sor.sayConsole(); // "Console: Sega"
Ok time to extend our class
function MiniGame() {};
MiniGame.prototype = new Game();
With the above code MiniGame has inherited the properties and methods of its parent class Game. If those methods and properties should only be available to the parent class we can override them at the child level.
MiniGame.prototype.setTitle = undefined;
MiniGame.prototype.getTitle = undefined;
var quacker = new MiniGame();
quacker.setTitle("Quack It"); // Undefined, womp womp
There’s more then one way to skin a cat, and there’s more than one way to implement inheritance and encapsulation in JS. I use your comments and feedback to guide the creation of future posts so please let me know what you’d like to see covered. Also if you have any questions please ask it in the comments.