In this article I will go through seven different ways to create objects in Javascript, pointing out the pros and cons in each of them.
Before starting, it is worth remembering that a Javascript object is a simple collection of properties. Each property is a key-value pair. The value can be a primitive type, an object, or a function. Properties can be added, updated or removed at any time.
1. Object constructor
The simplest way to create an object is to use theObject constructor:
var person = new Object();
person.name = "Diego";
person.getName = function(){
return this.name;
};
The main advantage of this approach is its simplicity. On the other hand, instantiating multiple objects of the same type leads to a lot of code duplication. Moreover, it is not a compact construct which means it is not intuitively straightforward in pointing out to where the object's construction ends.
2. Literal notation
var person = {
person.name : "Diego",
person.getName : function(){
return this.name;
}
}
While the literal notation is more compact and elegant than the Object constructor, it is still not reusable.
3. Factory function
The Factory function allows to encapsulate and re-use the logic for creating similar objects. It leverages any of the previous constructs for this.Either:
var newPerson=function(name){
var result = new Object();
result.name = name;
result.getName = function(){
return this.name;
};
return result;
};
var personOne = newPerson("Diego");
var personTwo = newPerson("Gangelo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Gangelo
Or:
var newPerson=function(name){
return {
person.name : name,
person.getName : function(){
return this.name;
};
};
var personOne = newPerson("Diego");
var personTwo = newPerson("Gangelo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Gangelo
Code re-use and encapsulation are the main advantages of this pattern. Now suppose you have an object X at a certain point in your code. How do you determine if X is a
person or not? You could use some ad-hoc technique but the most elegant approach would be to interrogate the instanceOf operator.
4. Function Constructor
In Javascript it is possible to call any function with thenew operator in front of it. Given a function F, for
new F():
- a new empty object X is created.
- X is set as context for F meaning throughout F
thispoints to X. - X is returned as result of F
function Person(name){
this.name = name;
this.getName = function(){
return this.name;
};
};
var personOne = new Person("Diego");
console.log(personOne.getName()); // prints Diego
console.log(personOne instanceOf Person); // prints true
console.log(personOne.constructor === Person); // prints true
console.log(personOne instanceOf Object); // prints true
This time instanceof behaves the way we desired. The constructor pattern is compact, reusable and gives a classical OO syntax.
Still, it is not perfect! In our example the field
getName is a function.
In Javascript functions are objects. Same function defined ten times means ten different objects created. Escalate this to a thousand and realize how much memory is being wasted! It would be nice if all instances of
Person share the same getName object, since this holds behavior and not data.
5. Prototype
Functions are very special in Javascript. They are objects, they can create other objects and they automatically get a field calledprototype.A prototype is a plain object with a single field, called
constructor, pointing to the function itself. What makes it special is that every object created through a function inherits the function's prototype.
function Person(){};
Person.prototype.name = "Diego";
var personOne = new Person();
var personTwo = new Person();
console.log(personOne.constructor == Person); // prints true
console.log(personOne.name); // prints Diego
console.log(personTwo.constructor == Person); // prints true
console.log(personTwo.name); // prints Diego
Let's see more in detail what happens:
- Line 1:
Personfunction is created. It automatically gets theprototypefield. - Line 2: A field called
nameis added to Person'sprototype. - Lines 3 and 4: Two instances of Person are created. They both get a field called
__proto__pointing to Person's prototype. - The last four lines show how the two objects share all properties present in Person's prototype
name field accessible directly from the object and not through the __proto__ field?In order to answer this, we first have to understand how property lookup works in Javascript.
Suppose you want to access a field called
name in an object foo:
- if
foohas a propertyname, the relative value is returned. - if
foodoes not have a propertynamebut__proto__does,__proto__'s value is returned. - if neither
foonor__proto__have the property, then__proto__'s prototype is checked. And so on...
__proto__. Therefore, it is better if you never try to access it. The prototype pattern solves the issues encountered within the function constructor.
On the other hand, the opposite problem arises: All instances share the same fields. This is good for functions, but not for the rest!
personOne.name = "Filippo"; console.log(personOne.name); // prints Filippo console.log(personTwo.name); // prints Filippo
6. Function/Prototype combination
The function/prototype combination, as you would imagine, takes advantage of both approaches :)
function Person(name){
this.name = name;
};
Person.prototype.getName = function(){
return this.name;
};
var personOne = new Person("Diego");
var personTwo = new Person("Filippo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Filippo
console.log(personOne.getName === personTwo.getName) //prints true
While sharing behavior (the getName function), each object has its own data and state.
7. Singleton
Sometimes, you may want to make sure that only a single instance of a certain class exists.To get a Singleton in Javascript is as simple as defining and invoking the constructor at the same time:
var singleton = new function(){
this.name = "ApplicationName";
};
Conclusions
In this article we have seen the different techniques available for creating objects in Javascript.Things will change a lot when Harmony will be on the road. Until that day however, we have to keep using these techniques, which are not that bad after all :)
nice overview .. thanks for putting it together!
ReplyDeleteyep. thanks a bunch
ReplyDeleteGood one...
ReplyDeleteI would like to learn the usage and advantages of underscore.js over other js frameworks, can you share that if you have any idea
,
ReplyDeletenice
ReplyDeleteGud 1.. Little more explanation would have made it to next level
ReplyDelete