Object Oriented Programming in JavaScript

First, what is Object Oriented Programming (OOP)?

“Object-oriented programming (OOP) is a programming paradigm that uses "objects" &ndash data structures consisting of datafields and methods &ndash and their interactions to design applications and computer programs.”

JavaScript uses the Prototype Pattern and therefore lacks the concept of a Class. Instead OOP in JavaScript relies on attaching objects and functions to the prototype of an object, which can then be referenced by each object instantiation.

The following example takes the native Date object and adds a static array of month names to it. Then we attach the function getMonthName to the prototype of Date, which will return the month name for the instantiated Date object:

Example 1: Define monthNameList and getMonthName

Date.monthNameList = [January, February, March, April, May, June,July, August, September, October, November, December];
Date.prototype.getMonthName = function() {
	var i = this.getMonth();
	return Date.monthNameList[i];
}

Line 1, attaches the array of month strings to the native Date Object. This array behaves like any other JavaScript variable, but best practice should treat variables attached directly to native objects as final (immutable) variables. Here is an example of how new Date instantiations will behave:

Example 2: Instantiate a New Date

var date = new Date();
date.setMonth(0);
var month = date.getMonthName();

Here we instantiate a new Date object (date) and set its month to 0, which is the month January in JavaScript (0=Jan, …, 11=Dec). Then, call the new method getMonthName on the date object, which will return the string January. You can prototype any JavaScript object, including native objects, as we did in this example. However you should never attach values to the prototype of Object, as doing so will break for (var i in object) {…} loops. You should also be wary of attaching functions to Array, unless you know how it will affect the other JavaScript Libraries you are using.

Some objects, such as the native string object are never instantiated with the new operator, but nonetheless, all strings will have all the methods attached to their prototype. As will objects like Array, Object, and Regex, even when instantiated with their respective short-hand notations ([], {}, /…/).

Attaching objects and functions to the prototype of native objects is useful, but it is far more powerful to use OOP with your own objects. Here is an example creating a custom object ArrayUtils:

Example 3: Custom Object

var ArrayUtils = function() {};
// removes empty elements from arrays
ArrayUtils.prototype.compact(arr) {
	var newarr = [];
	for (var i = 0, j = arr.length; i < j; i += 1) {
		var value = arr[i];
		if (value) {
			newarr.push(value);
		}
	}
	return newarr;
}
var arrayMgr = new ArrayUtils();
var initValues = [a, b, c];
initValues[1] = null;
newValues = arrayMgr.compact(initValues);

First, create the ArrayUtils object and attach the function compact to its prototype. This function removes empty values from an array. Then, we instantiate the ArrayUtils object as arrayMgr, which has the compact function. Next, create an array with values 0=a, 1=b, 2=c and set the value at index 1 to null. Then put the initValues array through the compact function, creating the newValues array with values 0=a, 2=c.

The last part of OOP to discuss when attaching methods to the prototype of an object is the this keyword, which is the functional context. In most cases it will refer to the instantiated object unless you are nesting functions or using event callbacks. Anonymous or unattached functions will execute in the window context, but when referencing methods attached to or on an instantiated object, this refers to the object itself. So all functions attach to an objects prototype can reference the instantiated object with the this keyword. Example 1 used this to reference the instantiated dates getMonth function.

Lastly, it is important to mention that maintaining functional context (sometimes referred to as scope) in JavaScript can be complicated. For additional reading, see How To Preserve Scope in JavaScript.