Object Oriented JavaScript – Part 1

by Prasanth Gullapalli

In this article I will discuss multiple ways of creating objects in JavaScript. And in the next part of this article, I will cover Inheritance in JavaScript.

In JavaScript, Objects can be created in two ways:
(a) Using object constructor:

var person = new Object();
person.name='Prasanth';
person.company='Pramati'
person.alertName=function(){
	alert(this.name);
}

(b) Using object literal notation:

var person = {
	name:'Prasanth',
	company:'Pramati',
	alertName=function(){
		alert(this.name);
	}
}

Generally this is the preferred way of creating an object.

Suppose you have to create person object in multiple(say three) places, then we have to duplicate the code across multiple places. To avoid this, the object creation can be abstracted to a function that can be used. This can be done in multiple ways:

1. Factory Pattern: Here we create an function that encapsulates the object creation logic:

function createPerson(name, company){
	var o = new Object();
	o.name = name;
	o.company = company;
	o.job = job;
	o.alertName=function(){
		alert(this.name);
	}
	return o;
}

Here is how we can create multiple person objects now:

var person1 = createPerson('Prasanth','Pramati');
var person2 = createPerson('Naresh','StackOverflow');

Here there are two problems:
(i) When a function like alertName is defined, it is logically equivalent to calling this piece of code:

o.alertName=new Function("alert(this.name)");

So person1 and person2 objects have got different alertName functions created i.e.

alert(person1.alertName == person2.alertName) //false

(ii) We could have classified the object as Person rather. This object identification issue gets resolved by using constructor pattern.

alert(typeof person1); //"object"

2. Constructor pattern: Here is how this can be implemented:

function Person(name, company){
	this.name = name;
	this.company = company;
	this.job = job;
	this.alertName=function(){
		alert(this.name);
	}
}

This looks pretty much like how we define a constructor for a class in Java. Now we can create multiple person objects as follows:

var person1 = new Person('Prasanth','Pramati');
var person2 = new Person('Naresh','StackOverflow');

When we call a function with new keyword, here is what will happen behind the scenes:
(i) Create a new object
(ii) Assign ‘this’ value of constructor(newly defined function) to the newly created object
(iii) Execute the code inside the constructor
(iv) Return the newly created object
So to create a person object, call the function with the new keyword. Whenever an object is created, it has a constructor property which points to itself. In this case:

alert(person1.constructor) //Person
alert(person2.constructor) //Person

Now we have identified what kind of object we have created. But a better way of doing this is to use instanceof method.

alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true

Note that constructors too are normal JS functions. It is the new keyword which does the magic. You can still call the Person function without using ‘new’.

var object = Person('Prasanth','Pramati');

In this case the alertName function is defined on window object as this refers to the global context object now. We can invoke it by calling window.alertName(). But note that still we get multiple function objects created for alertName when we define two different person objects. This can be rectified as follows:

function Person(name, company,job){
	this.name = name;
	this.company = company;
	this.job = job;
	this.alertName=alertName;
}
function alertName(){
	alert(this.name);
}

Suppose we have more number of alertName like functions, this clutters up the global scope. This problem is addressed by Prototype Pattern

3. Prototype Pattern: When a function is created, it by default gets a prototype property which basically consists of properties and methods that should be available to all the objects of particular reference type. So all the properties and methods are shared across object instances. The prototype internally will have a pointer internally to the constructor of function. This is the reason why all objects will by default get a constructor property. It is in fact defined in the prototype object. Properties/functions defined on prototype are in a way similar to static properties defined in a class in Java. Similar to static properties, if you make changes to any properties/methods defined in the prototype they will visible across all the instances. So it is good to see that now multiple function objects are not created for multiple instances of same reference type if we define them on prototype. Here is the example:

function Person(name, company){
	this.name = name;
	this.company = company;
	this.job = job;
}

Person.prototype.alertName=function(){
	alert(this.name);
}

var person1 = new Person('Prasanth','Pramati');
var person2 = new Person('Avinash','Imaginea');

alert(person1.alertName == person2.alertName); //true

When we look for a property/method on an object, JavaScript first checks if they exist on object. If not found, it goes and looks at object prototype and returns it if found. Now how to identify when the property is defined in constructor or on prototype? We can use hasOwnProperty method:

alert(person1.hasOwnProperty('name')) //true
alert(person1.hasOwnProperty('alertName')) //false

Now how do we find out that property is defined on prototype:

alert(('name' in person1) && !(person1.hasOwnProperty('name'))) // true

Suppose we have so many properties to be defined on prototype. Instead of adding like Person.prototype.property1, Person.prototype.property2 we can use a more compact literal notation here:

function Person(name, company,job){
	this.name = name;
	this.company = company;
	this.job = job;
}

var prasanth = new Person('Prasanth', 'Pramati', 'Engineer');

Person.prototype={
	alertName : function(){
		alert(this.name);
	},
	alertCompany : function(){
		alert(this.company);
	},
	alertJob : function(){
		alert(this.job);
	},
	// newly added method
	sayHi: function(){
		alert('Hi Dude!');
	}
}

var madan = new Person('Madan', 'ServiceBoy', 'CEO');
alert(prasanth.constructor == madan.constructor);
// What is the output? True/False??

As both prasanth and madan are person objects, we expect that their constructor property should refer to Person. The code looks like it will alert True. But it will alert False. Recall that function will have a reference to prototype object. Now with the code above, we are overriding it. So the new prototype object’s constructor property no more refers to Person. It refers to Object as it is created using Object literal notation. So prasanth.constructor refers to Person where as madan.constructor refers to Object. This can be easily fixed by including constructor property in our new prototype object literal

Person.prototype={
	constructor : Person,
	alertName : function(){
		alert(this.name);
	},
	alertCompany : function(){
		alert(this.company);
	},
	alertJob : function(){
		alert(this.job);
	},
	// newly added method
	sayHi: function(){
		alert('Hi Dude!');
	}
}

As both objects refers to different prototypes without the fix given above, we cannot call sayHi on prasanth object. It will throw an error saying that the method is not defined. Now after the fix, it will work fine as property look up is done on prototype dynamically when it is not found on the object.

Also note that it is good to define properties inside the object constructor and methods on the prototype. Here is an example:

function Person(name){
	this.name = name;
}

Person.prototype.qualifications=['B.E.(Hons)'];
Person.prototype.alertName : function(){
	alert(this.name);
}

var dawood = new Person('Dawood');
var prasanth = new Person('Prasanth');

alert(dawood.qualifications) // B.E.(Hons)
alert(prasanth.qualifications) // B.E.(Hons)

prasanth.qualifications.push('M.Sc(Hons)');
alert(dawood.qualifications) // B.E.(Hons), M.Sc(Hons)
alert(prasanth.qualifications) // B.E.(Hons), M.Sc(Hons)

This is unexpected. I want to add qualification only to Prasanth. It got added to the object which is defined on Prototype and hence is reflected in both the places. So to avoid this define properties inside the object constructor and methods on the prototype. So here is the ideal solution which actually is combination of both Constructor and Prototype patterns.

function Person(name){
	this.name = name;
	this.qualifications=['B.E.(Hons)'];
}
Person.prototype={
	constructor : Person,
	alertName : function(){
		alert(this.name);
	}
}

This will resolve all the problems we have discussed in the earlier approaches.

Advertisements

One thought on “Object Oriented JavaScript – Part 1

  1. “So prasanth.constructor refers to Prasanth where as madan.constructor refers to Object”
    may be typo, i think.
    “So prasanth.constructor refers to Person where as madan.constructor refers to Object”
    is correct, don’t you?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s