Javascript creating objects - multiple approaches, any differences?
7 ways to create objects in JavaScript :
1. Object constructor
The simplest way to create an object is to use the Object constructor: view plainprint?
var person = new Object();
person.name = "Diego";
person.getName = function(){
return this.name;
};
2. Literal notation
view plainprint?
var person = {
person.name : "Diego",
person.getName : function(){
return this.name;
}
}
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: view plainprint?
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:
view plainprint?
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
4. Function Constructor
In Javascript it is possible to call any function with the new 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 this points to X. X is returned as result of F view plainprint?
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
5. Prototype
Functions are very special in Javascript. They are objects, they can create other objects and they automatically get a field called prototype. 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. view plainprint?
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
6. Function/Prototype combination
The function/prototype combination, as you would imagine, takes advantage of both approaches :) view plainprint?
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
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: view plainprint?
var singleton = new function(){
this.name = "ApplicationName";
};
In approaches #2 and #3 the constructor
property of the resulting objects will be different.
In practice it means that the second approach allows you to instantiate more than one object using the anonymous constructor function:
x = new function() { alert(1) };
y = new x.constructor; // shows the message too
The top answer to Module pattern vs. instance of an anonymous constructor includes a quote from Douglas Crockford in which he explains why he thinks the approach #3 is better than #2.
The first and third approach are almost the same, in a way they both create an object literal, which is a direct child of Object
class. The difference between them is that in the third approach you may have some sort of encapsulation of properties:
var obj = (function() {
var prop = {};
return {
prop2: function(){ return prop };
}
})();
Performance-wise you might consider that the third approach creates closure, while the first one does not!
However in the second approach you are merely creating a new object from an anonymous class which is not a direct child of Object
class.
The correct form of the second approach is this (at least that's ecma standard):
var obj = new function() {
var prop1 = value1;
this.prop2 = value2;
}();
The difference between approach 2 and 3 is only their inheritance chain: (assuming obj2 is from 2nd approach and obj3 is from 3rd approach)
obj2.__proto__ == Object.prototype; // false
obj3.__proto__ == Object.prototype; // true
obj2 is created from an anonymous class itself:
obj2.__proto__.__proto__ == Object.prototype; // true (there's 2 level of inheritance here)