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.