I've put these together with the help of others and several resources. I've made a fiddle of everything, and the stripped down code is posted below.
Basically I've learned how to use each of these patterns but I'm curious about the more fundamental differences between these approaches. Downstream code is practically identical with any of these patterns, but is there a reason why one should use one over another, beyond personal preference? Also though I've tried to gather up the most common patterns, please suggest your own if it's better.
Pattern 1 (Object Based):
var mouseDiff = {
"startPoint" : {"x" :0, "y" : 0},
"hypotenuse" : function(a,b) {
// do something
},
"init" : function(){
// do something
}
}
mouseDiff.init();
Pattern 2 (Most traditional as far as I know):
function MouseDiff() {
this.startPoint = {"x" :0, "y" : 0};
}
MouseDiff.prototype.hypotenuse = function(a,b) {
// do something
}
MouseDiff.prototype.init = function() {
// do something
}
var myMouse = new MouseDiff;
myMouse.init();
Pattern 3 (Making use of closure):
var MouseDiff2 = (function() {
var startPoint = {"x" :0, "y" : 0};
var hypotenuse = function(a,b) {
// do something
};
return {
hypotenuse: hypotenuse,
init : function(){
// do something
}
};
}());
MouseDiff2.init();
http://www.jsoops.net/ is quite good for oop in Js. If provide private, protected, public variable and function, and also Inheritance feature. Example Code:
This has been answered elsewhere many times before but just to offer up some variety. ds.oop is a nice way to declare classes with constructors in javascript. It supports every possible type of inheritance (Including 1 type that even c# does not support) as well as Interfaces which is nice.
I do not know enough about JavaScript to tell you what if any performance differences exist between these approaches. Here are just two differences between these I noticed. I'm sure there are others.
Pattern 1 creates one object with those properties, including attached methods. Pattern 2 allows us to easily create many objects with the same methods attached, without rewriting them.
Pattern 3 is like a factory. Instead of relying on prototype to automatically attach these methods, the factory just creates them anew and returns the object. The usage of a closure allows us to hide the "member variables" of the object. There is no way to access
startPoint
orhypotenuse()
except through the "public" interface returned.Whenever I answer these types of theoretical JavaScript questions, I always fear there is some technical detail I am forgetting or overlooking. If so, let me know, and I will fix the answer.
Pattern two is my personally preference because it is the closest to traditional object oriented programming and allows for easy inheritance.
This post by John Resig (the guy behind JQuery) uses that method... http://ejohn.org/blog/simple-javascript-inheritance/
[edit]
In fact, I don't think methods 1 or 3 have any benefits. 1 is, as someone else said, a singleton and does not allow multiple instances and 3... I don't know where to start with 3.
Pattern 1 is a singleton. If you only need one such object, it's just fine.
Pattern 2 builds new objects, and takes advantage of the
prototype
object so that when a newMouseDiff
object is created, it will not create new copies of the functions (which are themselves data in JavaScript).Pattern 3 requires more memory in comparison to a regular singleton but it offers static privacy.
I like the following pattern, as it covers various features, though it is really a combination of the constructor (pattern 2) and closure (pattern 3):
There is one more possible way to do this.
Here we simply pass the namespace as an argument to a self-invoking function. The
privateVarialble
variable is private because it does not get assigned to the context.We can even set the context to the global object (with a one word change!). Inside brackets
(MouseDiff)
make it(this)
. This is a big asset for library vendors – who can wrap their features in a self-invoking function and leave it to the user to decide whether they should be global or not.