Last active
December 27, 2015 00:07
-
-
Save awongCM/75f68b9c786a7ad6ad60 to your computer and use it in GitHub Desktop.
Ways of creating Javascript objects Source: http://a-developer-life.blogspot.com.au/2011/11/7-ways-to-create-objects-in-javascript.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//1. Object 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 | |
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 | |
/* | |
* The Factory function allows to encapsulate and re-use the logic for creating similar objects. | |
* It leverages any of the previous constructs for this. | |
* | |
* 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 | |
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 | |
/* | |
* 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 | |
* | |
* 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 | |
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 | |
/* | |
* 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. | |
* | |
* Let's see more in detail what happens: | |
* Line 1: Person function is created. It automatically gets the prototype field. | |
* Line 2: A field called name is added to Person's prototype. | |
* 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 | |
* Why is the 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 foo has a property name, the relative value is returned. | |
* if foo does not have a property name but __proto__ does, __proto__'s value is returned. | |
* if neither foo nor __proto__ have the property, then __proto__'s prototype is checked. And so on... | |
* Due to time and space constraints, I will not talk more about prototypes except emphasizing that | |
* not all Javascript implementations provide access to __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 | |
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 | |
/* | |
* The function/prototype combination, as you would imagine, takes advantage of both approaches :) | |
* | |
* While sharing behavior (the getName function), each object has its own data and state | |
*/ | |
//7. Singleton | |
var singleton = new function(){ | |
this.name = "ApplicationName"; | |
}; | |
/* | |
* 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: | |
*/ | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment