Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Introduction to Object-Oriented JavaScript

4.92/5 (36 votes)
5 Aug 2008CPOL9 min read 2   436  
An introduction to writing object-oriented structures in JavaScript

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:

JavaScript
<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:

JavaScript
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.

JavaScript
..

function MyClass()
{
  this.MyData = "Some Text";
  this.MoreData = "Some More Text";
}

..

These properties can be accessed by:

JavaScript
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:

JavaScript
..

function MyClass()
{
  //Any properties created here
}

MyClass.prototype.MyFunction = function()
{
  //Function code here
}

..

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:

JavaScript
..

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:

JavaScript
..

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:

JavaScript
..

//Parent class constructor
function Animal(name)
{
  this.name = name;
}

//Inherited class constructor
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:

JavaScript
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:

JavaScript
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:

JavaScript
..

//Parent class constructor
function Animal(name)
{
  this.name = name;
}

//Parent class method
Animal.prototype.alertName = function()
{
  alert(this.name);
}

//Inherited class constructor
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:

JavaScript
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.

JavaScript
var d = new Dog("Fido");      //Creates an instance of the subclass
alert(d.name);                //Retrieves data inherited from the parent class
d.setCollarText("FIDO");      //Calls a subclass method

Methods that are inherited in a subclass can also be called similarly with the variable name in place of the this operator:

JavaScript
var d = new Dog("Fido");      //Creates an instance of the subclass
d.alertName();                //Calls the inherited method

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:

JavaScript
..

//Parent class constructor
function Animal(name)
{
  this.name = name;
}

Animal.prototype.speak = function()
{
  alert(this.name + " says:");
}

//Inherited class "Dog" constructor
function Dog(name)
{
  Animal.call(this, name);
}

Dog.prototype.speak = function()
{
  Animal.prototype.speak.call(this);
  
  alert("woof");
}

//Inherited class "Cat" constructor
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:

JavaScript
var d = new Dog("Fido");     //Creates instance of Dog
d.speak();                   //Calls Dog's speak() function
 
var c = new Cat("Lucy");     //Creates instance of Cat
c.speak();                   //Calls Cat's speak() function

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)