There are so many ways to create objects in Java Script,
it be so flexible after all. So what is the right way to create an object. Constructor
pattern, Prototype pattern, Object literal?
What is it?
Before going there, let us try to get some basics
cleared about JavaScript.
Is Object Oriented
programming even possible in JavaScript?
Well it has objects! The object can contain data and can
have methods acting on that data and can even have other objects. It does not have classes but have constructors, it does
not have class oriented inheritance but does have prototype based inheritance.
It kind of looks like we have all the ingredients
necessary to create object and object oriented programming in JavaScript.
We all know JavaScript has private variables. A variable
defined inside a function using the "var" keyword lives within the scope of the
function and is not accessible outside the function.
What happens when we do not use "var" keyword to declare
the variable? We might talk a little about it, might cross through “this”, but
can be a different story some other day.
So back to the question. What is the right way to create
an Object/Classes in JavaScript?
Let us try with what we know and lets us try to create an
object called Person
var Person = {
firstName : 'John',
lastName : 'Cody',
fullName : '',
message : '',
createFullName : function () {
fullName = this.firstName + ' ' + this.lastName;
},
changeMessage : function (msg) {
this.message = msg;
},
getMessage : function () {
this.createFullName();
return this.message + ' ' + fullName;
}
}
Person.firstName = 'Eli';
Person.lastName = 'Flowers'
Person.changeMessage('welcome');
var message = Person.getMessage();
alert(message);
This object literal pattern. This is very close to how we are used to create classes.
If you do not care about private/encapsulation for that matter and you know you are not going to create the instance of this object. Then this might be a good choice for you. What is that private can do that public cannot do right? But this is not a class, it’s an object, cannot create instance on it and no encapsulation.
Let’s try something different.
var Person = function() {
this.firstName = 'John';
this.lastName = 'Cody';
var fullName = '';
this.message = '';
var _that = this;
var createFullName = function () {
fullName = _that.firstName + ' ' + _that.lastName;
}
this.changeMessage = function (msg) {
this.message = msg;
}
this.getMessage = function () {
createFullName();
return this.message + ' ' + fullName;
}
}
var person1 = new Person();
person1.firstName = 'Eli';
person1.lastName = 'Flowers'
person1.changeMessage('welcome');
var message = person1.getMessage();
alert(message);
This is a constructor pattern. So is it a Class or Object. Well both. We can make use of the object Person as is when required. It is a function after all. Or create a new instance of this function by the use of the “new” keyword.
There are few things that we need to keep in mind with
this type of pattern.
- Whenever a function is called, it gets a special
variable called “this” and refers to the global scope. What global scope is
depends on the scope of the function itself.
- Whenever an instance of the function is created
using the keyword “new”, “this” refers to the function itself and the “new”
also causes the code inside the function to execute. Hence constructor
pattern.
- Anything that is attached to “this” becomes
public and anything that is declared with “var” is private.
- A function attached to “this” is called a
privileged function and can access private variables and function and other
variables and functions attached to “this”.
- Private Functions have access to other private
variables and function.
- Private functions does not have direct access to
variables and functions attached to “this”. The way we achieve this by creating
a private variable called “_that” and assigning it to “this”.
- Any Private variable or function is available to
all the other private functions and all the other functions attached to “this”.
How this is possible read about Scope in JavaScript.
- A variable or function that is not declared with
“var” or not attached to “this” gets attached to the Global Scope, i.e. to the
scope where the function itself is defined. Again read more about Scope and
Closures.
This achieves pretty much what we want, but sometimes the entire thing with “this” and “that” can become confusing. And for people who want to want to stick to true private.
Let as try something a little more different.
var Person = function () {
var firstName = 'John';
var lastName = 'Cody';
var fullName = '';
var message = '';
var createFullName = function () {
fullName = firstName + ' ' + lastName;
}
var setMessage = function (msg) {
message = msg;
}
var setFirstName = function (fName) {
firstName = fName;
}
var setLastName = function (lName) {
lastName = lName;
}
var getMessage = function () {
createFullName();
return message + ' ' + fullName;
}
return {
setFirstName: setFirstName,
setLastName: setLastName,
setMessage: setMessage,
getMessage: getMessage
};
};
var person1 = new Person();
person1.setFirstName('Eli');
person1.setLastName('Flowers');
person1.setMessage('welcome');
var message = person1.getMessage();
alert(message);
This is Revealing Pattern. Thanks to Christian Heilmann. The thing with this type of pattern is that it requires "getters" and "setters" for properties. Most of us coming from the traditional Java programming can appreciate this and don’t find it complex. It is also kind of like as if the class implements an Interface.
All this good but there is one slight problem. Every time an instance of the class is created the newly created object gets the copy of variables and functions.
Now, copy of variables is fine, we want the data specific to the object, but functions? they are simply going to act on the data. Why need copies of them.
Here is where Prototype comes handy. Anything that is created on a prototype is shared among all the instances. All we have to do is create public functions on the prototype.
var Person = function () {
var welcomeMessage = 'welcome';
var fullName = '';
var firstName = '';
var lastName = "";
var createFullName = function () {
Person.prototype.setFirstName('asdsad');
fullName = firstName + ' ' + lastName;
};
var Person = function () { };
Person.prototype = {
getFullName: function () {
createFullName();
return welcomeMessage + ' ' + fullName;
},
setFirstName: function (fName) {
firstName = fName;
},
setLastName: function (lName) {
lastName = lName;
},
ChangeMessage: function (mesg) {
welcomeMessage = mesg;
}
}
return new Person();
};
var person1 = new Person();
person1.setFirstName ('Eli');
person1.setLastName('Flowers');
person1.ChangeMessage('welcome');
var message = person1.getFullName();
alert(message);
One of the problem with prototype is that it cannot access private variables and functions, and for that reason we have introduced closures and also to keep the code organized for those of us who worry how class are created and it also does not clutter the global scope. Everything is still inside the scope of Person.
The other problem is that every time an instance is created the entire code is executed, including the binding of the prototype. For some of us this is performance problem. The way to take care of this problem is to bind the prototype only if an expected public function is not already available.
This will result in binding the prototype only once when the first instance is created and after that for all the other instances the check will kick in. Unfortunately this fix will not work in our example above as we are creating the function all over again to generate a closure to achieve the class affect. Hey at least we saved some memory.
Yet another problem is that private functions cannot access prototype functions directly.
Why do you need private functions and variables anyways? I understand encapsulation is on your mind, want to make sure that properties or internal data does not get changed accidentally or intentionally by other programmer whatever… whatever.
Remember you cannot compile the code into binary, you are screwed anyways, the code is always available, so if anyone want to mess it up they will mess it up weather you implement true private or not, weather you give it to other team members or sell it. Will minify help, probably.
One of the other techniques programmers use is naming conventions, use and underscore “_” for anything that you intend to make private.
(function () {
var Person = function () {
this._fullName = '';
this.welcomeMessage = '';
this.firstName = '';
this.lastName = "";
_that = this;
this._createFullName = function () {
this.ChangeMessage('Namaste');
this._fullName = this.firstName + ' ' + this.lastName;
};
}
Person.prototype = {
constructor: Person,
getFullName: function () {
this._createFullName();
return this.welcomeMessage + ' ' + this._fullName;
},
ChangeMessage: function (mesg) {
this.welcomeMessage = mesg;
}
}
this.Person = Person;
})();
var person1 = new Person();
person1.firstName = 'Eli';
person1.lastName = 'Flowers';
person1.ChangeMessage('Welcome');
var message = person1.getFullName();
alert(message);
I am not saying you should not consider “private” and stuff. You are the designer of the code and you will know how to engineer and what works best for you. Depending on your need you can use any one or combination of the patterns.
Whatever you decide to do few things to keep in mind, do not clutter the Global Scope, worry about memory leaks, and code optimization, and keep code organized. So read more about Scope, Closures and how “this” behaves.
Happy Programming.