Categories
JavaScript Uncategorized

JavaScript Patterns in Object Oriented Programming and Inheritance

When I first started learning JavaScript, I would challenge myself by reading source code I would find at Github from some open-source repo. Other times, I would just view > source a website and look under the hood. This, I thought, would verify that I was indeed understanding the theory and concepts I learned from books. Often, however, these autodidactic activities resulted in my spirits crushed as I encountered code blocks that were too convoluted and elaborate; code that would use all those little building blocks of the language (logical operators, keywords, variable scope, etc) together in order to build a complex architecture I was completely ignorant of and intimidated by. In short, I would just run into code that was well beyond my limited comprehension.

One thing I did notice was that there was a lot of similarities between code blocks. Which meant there was probably a fairly standardized, conventional pattern being used.  Lately, I’ve finally got a chance to be introduced to these patterns thanks to my current university class. And so I though’t it’d be beneficial to share some of these pervasive patterns that you’ll likely find at some point in your journey as a JavaScript developer. So without further ado, let’s get to it.

Factory Pattern

The first time I heard about this pattern was on Addy Osmani’s book which covers this pattern (and so many others) much more extensively. I’m gonna show you the TLDR; version. In essence, the factory pattern is a function that creates an object and returns it so that it can be stored in a variable, or chained to other methods, etc.

Here is an example of a simple factory:

function createBand(name, country, num){

  // declare local variable to store generic Object instance
  var band = new Object();
 
  // now set the instance properties and methods
  band.name = name;
  band.country = country;
  band.numberOfMembers = num;
  band.greeting = function(){
     console.log("Hello, we are " + this.name + " and we're from " + this.country);
 }

  // now return the instance just created
  return band;

}

 

With this function defined, we can instantiate objects by calling the function and storing the returned object in a variable outside of the factory function scope. Then we can call the methods that are shared by all instances of the same band Object type, or all objects created with our createBand() function

var radiohead = createBand("Radiohead", "England", 5);
var af = createBand("Arcade Fire", "Canada", 6);

radiohead.greeting(); // "Hi we're Radiohead and we're from England"
af.greeting(); // "Hi we're Arcade Fire and we're from Canada"

 

Disadvantages

Though this pattern lets the programmer create Objects that share the same methods and properties, the objects created do not have a type other than the generic JavaScript Object object. This is not very useful in practice because if at some point we neededto know if radiohead is related to af there is no way to tell since both objects don’t belong to a distinct type, or class. They just belong to the Object type, which is very broad. Strings, Arrays, Functions, are all part of the Object type as well, so wee need to fix this ambiguity.

To define the type, we will need a constructor function.

 

 

Constructor Pattern

The constructor pattern lets us construct objects that belong to a specific type or class. In our previous example, we had no way to find out if the objects being referenced by the radiohead and af variables were similar, or had the same property fields and methods. In other words we did not know if those two objects were part of the same class.

The key in the constructor pattern is the new keyword. We define a constructor function, and then instantiate the objects defined by such function using the new keyword. Example

/* Band Constructor creates Band Objects
====================================*/

function Band(name, country, num){
  // set instance properties, and have a default if no arguments passed.
  this.name = name || 'Not Given';
  this.country = country || 'Not Given';
  this.numberOfMembers = num || 'Not Given';

  // set instance method
  this.greeting = function(){
     console.log("Hello, we are " + this.name + " and we're from " + this.country);
 }

}

// instantiate new Band Object
var strokes = new Band("The strokes", "U.S.A", 5);

//check if strokes is part of the Band object class
console.log(strokes instanceof Band); // true

 

* Coding convention: All constructor function names begin with an uppercase letter i.e Band

Disadvantages

There is a couple of potential pitfalls when dealing with constructors. First, if your code invokes a constructor function without the new keyword, the properties defined for the object we defined are now applied or added to the global object, which, in the DOM’s case, is the window object. So, to illustrate what I mean:

// Suppose we just invoke the Band constructor without the new keyword
Band('garage band', 'Italy', 4);

// now the window object has those properties and method
console.log(window.name); // Garage Band
console.log(window.country); // Italy

window.greeting(); //"Hi we're garage band and we're from Italy"

The other obstacle that constructor functions impose, is that with each instance of an object has it’s own definition of each method. Suppose we create 100 Band Objects. All it’s well until we decide that, for some reason, we want to change the message returned by the greeting() method. In this scenario we would have to change the method 100 times! This is a maintainability nightmare, and not very efficient.

With that said, there’s a solution to this problem. Enter the famous prototype.

 

Prototypes and Inheritance patterns

This feature in JavaScript is what enables us as developers to start building classes, and objects that inherit from others. Now, prototypes were perhaps the toughest pill to swallow while learning these advanced JavaScript concepts because the concept is very, very abstract. But nonetheless I will do my best to explain them to the best of my ability.

Basically a Prototype in JavaScript is an abstract, “invisible” object (meaning you don’t really see it in your source code) from which other related objects inherit. Whenever we define a new object we are actually creating it’s prototype as well. All instances of an object created via a constructor will inherit those properties that were set in the original definition of the constructor function.

All objects in JavaScript (native or created by developers) inherit properties and methods from their respective prototypes. For example, all strings created in JavaScript have the toLowerCase() method because they inherit it from the native String Object that comes in the JavaScript core. Because of this inheritance relationship, we as programmers benefit greatly since we do not have to define a toLowerCase() function every time we want to create objects of the String type; rather all strings we create have that method available to them, at any time.

To illustrate inheritance using native objects, let’s try and access the toLowerCase() method, override it with some code, and see if all String objects experience the change:

var string1 = "NFL";

console.log(string1.toLowerCase()); // "nfl" -- works as expected

// now let's override the prototype's method with a string message
String.prototype.toLowerCase = function(){ return "The method has changed");}

// let's test
console.log(string1.toLowerCase()); // "The method has changed"

// to verify let's create another string object and see
var string2 = "NBA";

console.log(string2.toLowerCase()); // "The method has changed"

 

Overriding native object’s methods and properties is something you don’t want to do, ever, but this example hopefully illustrates the nature of the prototype and prototypal inheritance.

Now, let us combine the modularity of constructor functions, with the efficiency of prototypal inheritance to create a Band class.

To do this, we use the constructor function to help us pass in variables unique to each object during instantiation, known as instance variables, and we use the prototype approach to define any property or method that will be the same in all instances of the object.

 

// define instance variables unique to each object instance through the constructor function
function Band(name, country, num){
  
  // set instance properties, and have a default if no arguments passed.
  this.name = name || 'Not Given';
  this.country = country || 'Not Given';
  this.numberOfMembers = num || 'Not Given';

}


// Define common data and functionality in the prototype
Band.prototype = {

	greeting : function(){
     console.log("Hello, we are " + this.name + " and we're from " + this.country);
 },

 	micCheck : function(){
 		console.log("1..2..3..check...check...1..2..3");
 	}


}


// Instantiate 2 Band objects
var radiohead = new Band('radiohead', 'UK', 5);
var garage = new Band('Garage band', 'Italy', 4);


// log out their uniqe properties
console.log(radiohead.numberOfMembers); // 5
console.log(garage.numberOfMembers); // 4


// invoke the inherited method
radiohead.micCheck(); // "1..2..3..check...check...1..2..3"
garage.micCheck(); // "1..2..3..check...check...1..2..3"



// Now, let's try overriding the micCheck method for all instances of Band

Band.prototype.micCheck = function(){

		console.log("This method has been changed for all Band Objects");

}


radiohead.micCheck(); // "This method has been changed for all Band Objects"
garage.micCheck(); // "This method has been changed for all Band Objects"

 

Inheritance with Subtypes

Sometimes we have to deal with a multi-layered hierarchy of objects in our application. So far our code has created a Band Object and instantiated Bands that shared a common prototype. But what if our application demands a more specific class hierarchy. What if we needed to create Rock bands, or Country Bands specifically? And what if we wanted them to share methods and properties of the Band type, but also have methods and properties of their own?

Luckily there’s a pattern that enables this:

// first we define our subtype
function CountryBand(state, toursInternationally){
	
	this.state = state || "State not available";
	this.internationalTour = toursInternationally;
	
	
}


// we want our CountryBand to inherit the same methods from Band
// we do this by setting it prototype to an instance of Band

CountryBand.prototype = new Band();


// now we can add methods specific to CountryBand
// here we modify the greeting method by overriding it on the prototype
// this does not override Band's version of greeting()

CountryBand.prototype.greeting = function() {
		return "We are country as hell";
	};


//and we can add new properties that are common JUST to all country bands
CountryBand.prototype.twangLevel = "moderate";


//lets test by creating a new CountryBand
var cb = new CountryBand("Georgia", true);


// the new object is an instance of both types

console.log(cb instanceof Band); // true
console.log(cb instanceof CountryBand); // true

//test the new subtype unique properties
console.log(cb.state); // "Georgia"
console.log(cb.internationalTour); true
console.log(cb.twangLevel); // "Moderate"

// test the inherited properties
console.log(cb.name); // defaults to "not given"
console.log(cb.greeting()); // "we are country as hell"
console.log(cb.micCheck()); // "check check 1..2..3"

 

Conclusion

The patterns I’ve presented in this post are just a few of many, many more out there. But I’d say that these are fundamental in any JavaScript developer’s formation. The ability to create, modify, and extend an object’s prototype with custom properties and methods are a core skill in web application, framework, and plugin development. Once you begin to internalize these patterns, the task is not so daunting and scary anymore., isn’t it?