ronaaronson has touched on probably the most important concept of object-oriented programming (OOP) in JavaScript -- the Prototype chain. Prototypal inheritance is a confusing subject for programmers who are used to the Classical approach to creating objects in other programming languages, like Java and C++. In addition, most other programming languages used on the web, like PHP and Python, also use Classical OOP
Prototyping is elegantly simple, and is part of what makes OOP in JavaScript so
expressive. You can do a lot more with fewer lines of code in JavaScript than you can in other languages, owing entirely to the fact that
all objects in JavaScript inherit their properties and methods from other objects. At the top of this chain is the
Object object.
I could spend all day discussing which object-oriented paradigm is superior and we would never reach a conclusion, since each has its strengths and weaknesses.
While I highly recommend that if you're coming from another language you take the time to familiarize yourself with Prototypal Inheritance, it is not my goal here to convince you to use it. I personally think it's best to use Prototypal Inheritance, but I will not deny that there are many scenarios where a classical approach is beneficial, particularly when working in a team. The Class, the heart of classical OOP, can be functionally simulated in JavaScript.
The ConstructorCreating a class in classical OOP is an iterative process whereby you continually modify your class throughout the development of your program or script. However, there is one key component that every class needs: a
constructor.
In JavaScript, the constructor is a blueprint for building an object. It tells the JavaScript interpreter what values (variables), which are called
object members in OOP, that the new object will contain, and sets default values. Without further ado, here is an example of a constructor:
JavaScript Constructor
function MyClass(num) {
this.num = num;
}Of course, this can be seen in the above tutorial. What I'm going to introduce here is the concept of
access modification, whereby we designate that certain object members can only be touched by
object methods, as opposed to allowing the script to interface with object members directly, using the syntax
myObject.myValue.
Object members and methods that can be called directly are said to be
public. On the flip side, objects and members that can only be referenced from within the object itself are said to be (you guessed it)
private.
Languages that implement a well-defined classical approach to OOP will have the keywords
public and
private. These keywords are called
access modifiers. For example, in PHP5, to declare a public member called
$myNum, you would do something like this:
PHP Class
<?php
class MyClass {
// Public member
public $myNum;
// Class constructor
public function __construct($num) {
$this->myNum = $num;
}
}
?>
JavaScript posseses no such access modifiers. They are instead implicit; we can simulate the functionality of access modifiers by exploiting JavaScript's unique scoping.
Function ScopeIf you're used to programming in languages like C, you're probably inclined to
block scope, where any variables that are declared within a block are destroyed once the block scope is complete. Consider the following C program:
C Block Scope
#include <stdio.h>
int main() {
int myInt = 1;
for (int i = 0; i < 10; i++) {
int temp = i + myInt;
printf("The value of temp is %d.", temp);
}
printf("The value of temp is %d.", temp); // Generates compiler error because temp isn't declared in this scope
return 0;
}
The variable
temp is declared within the for-loop block. Once that loop finishes execution, the block scope is terminated and the variable is deleted. It cannot be accessed from the next level up, the
main() function.
On the flip side, let's take a look at how JavaScript handles this:
Functional Scope in JavaScript
function sillyFunction() {
var myInt = 1;
for (var i = 0; i < 10; i++) {
var temp = myInt + i;
alert("The value of temp is " + temp); // Outputs 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
}
alert("The value of temp is " + temp); // Outputs 10
}
sillyFunction();As you can see, in JavaScript, it doesn't matter where in the function you declare a variable, be it nested in a block or in the root function block, so long as you've declared the variable before you attempt to use it. For this reason, the following code is functionally equivalent to the last:
Delcaring Variables in One Line in JavaScript
function sillyFunction2() {
var myInt = 1, i, temp;
for (i = 0; i < 10; i++) {
temp = myInt + i;
alert("The value of temp is " + temp);
}
alert("The value of temp is " + temp);
}There are actually very good reasons for declaring all of your variables in one line, namely for debugging purposes. If you declare all of your variables in one spot, there's no hunting through your program to find what value you initialized that variable at.
Private, Public, and Privileged MethodsUsing this unique scope, we can create methods that are both accessible to everyone, and have access to private variables. Here's a constructor with a private variable and a public method:
Private Variables and Public Functions in JavaScript
function MyConstructor() {
var num = 1; // Private variable
}
// Public method
MyConstructor.prototype.getNum = function () {
return this.num; // Gah! this.num doesn't exist!
}"But wait", you're thinking, "we didn't assign
num as a member using the
this keyword. It doesn't exist." It is true that in its present form,
getNum won't work, however it is a misconception to think that
num doesn't
exist.
num will continue to exist until the object is destroyed, it just isn't accessible from the outside. However, think about the function scope that I just discussed. Because JavaScript uses function scope, any blocks contained within the
MyConstructor function has access to variables declared in
MyConstructor. If we re-engineer our
getNum method like this...
Privileged Methods in JavaScript
function MyConstructor() {
var num = 1;
this.getNum = function () {
return num;
};
}Because of the function scope,
getNum has access to the private num variable, which is local to MyConstructor.
getNum is said to be a
privileged function.
In the above two posts, you are presented with two ways of creating public methods. You've just learned that one of them, declaring methods from within the constructor using the
this keyword actually creates a privileged method. I won't cover those in any more detail. There is only one more piece to the OOP puzzle:
Private Methods in JavaScript
function MyConstructor() {
// Private variable
var num = 1;
// Private method
function addOne() {
return num + 1;
}
// Privileged method
this.getNumPlusOne = function () {
return addOne();
};
}When to use private, privileged, and public variables is at your discretion. I'm leaving out a lot here, so it's up to you to look into a general approach to classical OOP. In doing so you will learn how to create classes, and how to choose whether a method should be public or private.