Contents
Introduction
Many JavaScript programmers overlook or do not know of the ability to write object-oriented JavaScript. Whilst not conventionally an object-oriented language, JavaScript is a prototype-based language, which means that inherited classes are not derived directly from a base class, but rather are created by cloning the base class which serves as a prototype. This can be used to one's advantage in implementing encapsulation, inheritance and polymorphism in JavaScript, therefore creating a sense of object-orientation.
Object-oriented JavaScript also has several advantages. As it is an interpreted language, it means that methods and properties can be added to the class at any time, and do not have to be declared in the class constructor, like other object-oriented languages such as C++. As JavaScript supports variable data types, class properties do not have to take a fixed data type (such as boolean
or string
) but rather can be changed at any time. Furthermore, object-oriented JavaScript is more flexible and efficient than procedural JavaScript, as objects fully support encapsulation and inheritance and polymorphism can be implemented using the prototype
property.
Prerequisites
Although this is an introductory article to object-oriented JavaScript, it would be beneficial to have an understanding of object-oriented programming, as this article does not go into this aspect in too much detail. However, a list of key object-oriented programming terms are listed and defined below for some guidance in this respect.
Key Terms
Several key terms will be used in this article which are summarized below:
- Class: Definition of an object including it's methods and properties.
- Encapsulation: This is where the data passed around inside an instance of an object is kept contained within the instance of that object. When a new instance of the object is created, a new set of data for that instance is created.
- Inheritance: Where an object becomes a "child" object or subclass of another class, and the "parent" class's properties and methods are applied to the subclass.
- Polymorphism: Where a subclass of a class can call the same generic inherited function in its own context.
- Property: A variable associated with a class.
- Method: A function associated with a class.
A Simple Class in JavaScript
Defining a Class
A basic class can be implemented very easily in JavaScript. All that must be done in order to define a class is for a function
to be declared:
<script language="Javascript">
..
function MyClass()
{
}
..
</script>
These three lines of code create a new object called MyClass
, instances of which can be created with the new
operator, such as:
var c = new MyClass();
The function MyClass
also acts as the class constructor, and when a new instance of that class is called with the new
operator, this function is called.
Creating Class Properties
This code so far is just a simple class with only its constructor declared. To add properties to the class, we use the this
operator, followed by the name of the property. As previously stated, methods and properties can be created anywhere in JavaScript, and not just in the class constructor. Here is an example of adding properties to MyClass
.
..
function MyClass()
{
this.MyData = "Some Text";
this.MoreData = "Some More Text";
}
..
These properties can be accessed by:
var c = new MyClass();
alert(c.MyData);
This piece of code adds the property MyData
and MoreData
to the class. This can be accessed anywhere within the class constructor and the class methods using the this
operator, so MyData
can be accessed by using this.MyData
. Also note that unlike some object-oriented languages, class properties are accessed with a .
and not a ->
. This is because JavaScript does not differentiate between pointers and variables. If the class reference is stored in a variable when created, then the class properties can be accessed by the variable name followed by a .
then the name of the class property, in this example myData
, which is accessed with c.MyData
.
Creating Class Methods
As said earlier in the article, class methods are created using the prototype
property. When a method is created in a class in JavaScript, the method is added to the class object using the prototype
property, as shown in the following piece of code:
..
function MyClass()
{
}
MyClass.prototype.MyFunction = function()
{
}
..
For clarity, the method here is created by using = function()
. Equally, the method can be created by declaring function MyClass.prototype.MyFunction()
. What this code does is make MyFunction
a method of MyClass
using the prototype
property. This then gives MyFunction
access to any other methods or properties created in MyClass
using the this
operator. For example:
..
function MyClass()
{
this.MyData = "Some Text";
}
MyClass.prototype.MyFunction = function(newtext)
{
this.MyData = newtext;
alert("New text:\n"+this.MyData);
}
..
This piece of code creates the MyClass
class, then creates a property called MyData
in the class constructor. A method, called MyFunction
is then added to the MyClass
object, using the prototype
operator, so that it can access the MyClass
properties and methods. In this method, MyData
is changed to newtext
, which is the only argument of the method. This new value is then displayed using an alert box.
Encapsulation
Encapsulation is a useful part of object-oriented programming that "encapsulates" or contains data in an instance of a class from the data in another instance of the same class. This is why the this
operator is used within a class, so that it retrieves the data for that variable within that instance of the class.
Public, Protected and Private Members
Encapsulation is implemented in JavaScript by separating instance data within a class. However, there is no varying scale of encapsulation through the public
, protected
and private
operators. This means that access to data cannot be restricted, as seen in other object-oriented programming languages. The reason for this is that in JavaScript it is simply not necessary to do so, even for fairly large projects. As of this, class properties and methods can be accessed from anywhere, either inside the class or outside of it.
Encapsulation in Practice
An example of encapsulation can be shown below:
..
function MyClass()
{
this.MyData = "Some Text";
}
MyClass.prototype.MyFunction = function(newtext)
{
this.MyData = newtext;
alert("New text:\n"+this.MyData);
}
..
var c = new MyClass();
c.MyFunction("Some More Text");
var c2 = new MyClass();
c2.MyFunction("Some Different Text");
If called, c.MyData
would return "Some More Text"
and c2.MyData
would return "Some Different Text"
, showing that the data is encapsulated within the class.
Conclusion to Encapsulation
Encapsulation is an important part of object-oriented programming, so that data in different instances of a class are separate from one another; this is implemented in JavaScript by using the this
operator. However, unlike other object-oriented programming languages, JavaScript does not restrict access to data within an instance of a class.
Inheritance
Inheriting Properties
As said earlier in the article, there is no direct inheritance in JavaScript, as it is a prototype language. Therefore, for a class to inherit from another class, the prototype
operator is used, to clone the parent class constructor, and in doing so, inheriting its methods and properties. The parent class constructor is also called in the subclass's constructor, to apply all of its methods and properties to the subclass, as shown in the code below:
..
function Animal(name)
{
this.name = name;
}
function Dog(name)
{
Animal.call(this, name);
}
Dog.prototype = new Animal();
Dog.prototype.ChangeName(newname)
{
this.name = newname;
}
..
In the code example above, two classes are created — a base class called Animal
and a subclass called Dog
which inherits from Animal
. In the base class constructor, a property called name
is created, and set a value passed to it.
When an inherited class is constructed, two lines of code are needed to inherit from the base class, as demonstrated with Dog
:
Animal.call(this, name);
This line of code is called from within the subclass's constructor. call()
is a JavaScript function which calls a function in the specified context (the first argument). Arguments needed by the called function are passed also, starting from the second argument of call()
, as seen with name
. What this means is that the base class constructor is called from within the subclass constructor, therefore applying the methods and properties created in Animal
to the subclass.
The second line of code needed to inherit from a base class is:
Dog.prototype = new Animal();
What this line of code does is set the prototype for the inherited class (which will clone the parent constructor when used) to be a new instance of the parent class, therefore inheriting any methods or properties in methods in the subclass.
Notice also that once a subclass has inherited from a parent class, any data that needs to be accessed from the parent class can be accessed using the this
operator, from within the subclass, as the methods and properties are now part of the subclass object.
Inheriting Methods
Like properties, methods can also be inherited from a parent class in JavaScript, similar to the inheritance of properties, as shown below:
..
function Animal(name)
{
this.name = name;
}
Animal.prototype.alertName = function()
{
alert(this.name);
}
function Dog(name)
{
Animal.call(this, name);
this.collarText;
}
Dog.prototype = new Animal();
Dog.prototype.setCollarText = function(text)
{
this.collarText = text;
}
..
An inherited method can be called as so:
var d = new Dog("Fido");
d.alertName();
This would call alertName()
, which is an inherited method of Animal
.
Creating an Instance of an Inherited Class
Classes that inherit from another class can be called in JavaScript as a base class would be called, and methods and properties can be called similarly.
var d = new Dog("Fido");
alert(d.name);
d.setCollarText("FIDO");
Methods that are inherited in a subclass can also be called similarly with the variable name in place of the this
operator:
var d = new Dog("Fido");
d.alertName();
Conclusion to Inheritance
Inheritance is the one of three important concepts of object-oriented programming. It is implemented in JavaScript using the prototype
and call()
functions.
Polymorphism
Polymorphism is an extension on the principle of inheritance in object-oriented programming and can also be implemented in JavaScript using the prototype
operator. Polymorphism is where a subclass of a class can call the same generic inherited function in its own context. For example:
..
function Animal(name)
{
this.name = name;
}
Animal.prototype.speak = function()
{
alert(this.name + " says:");
}
function Dog(name)
{
Animal.call(this, name);
}
Dog.prototype.speak = function()
{
Animal.prototype.speak.call(this);
alert("woof");
}
function Cat(name)
{
Animal.call(this, name);
}
Cat.prototype.speak = function()
{
Animal.prototype.speak.call(this);
alert("miaow");
}
..
This code means that if an instance of Dog
is called and then Dog's speak()
function is called, it will override the parent class's speak()
function. However, although we want to do something different with each subclass's version of speak()
, we want to call the parent class's generic speak()
function, through Animal.prototype.speak.call(this);
, which calls the inherited function in the context of the subclass. Then after that we do something else with it, which for Dog
is alert("woof");
and for Cat
is alert("miaow");
If called, this would look like:
var d = new Dog("Fido");
d.speak();
var c = new Cat("Lucy");
c.speak();
The first two lines would alert "Fido says:" (the parent class's speak()
function) followed by "woof" (Dog
's speak()
function).
The second two lines would alert "Lucy says:" (the parent class's speak()
function) followed by "miaow" (Cat
's speak()
function).
Conclusion to Polymorphism
Polymorphism is a very useful part of object-oriented programming, and whilst in this article it is not pursued too deeply, the principles remain constant and can be applied like this in most aspects of polymorphism in JavaScript.
Conclusion
After reading this article you should be able to:
- Create classes with methods and properties
- Create inherited classes
- Create polymorphic functions
This is just an introductory article, but I hope you can use these learned skills for more complicated object-oriented structures.
History
- 20th July, 2008: Unmodified first copy
- 4th August, 2008: Edited the Encapsulation section