Skip to content

Instantly share code, notes, and snippets.

@awongCM
Last active December 27, 2015 00:07
Show Gist options
  • Save awongCM/75f68b9c786a7ad6ad60 to your computer and use it in GitHub Desktop.
Save awongCM/75f68b9c786a7ad6ad60 to your computer and use it in GitHub Desktop.
//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