How to set up JavaScript namespace and classes properly?
Solution 1
Do neither of those things.
Make a javascript "class":
var MyClass = function () {
var privateVar; //private
var privateFn = function(){}; //private
this.someProperty = 5; //public
this.anotherProperty = false; //public
this.someFunction = function () { //public
//do something
};
};
MyNamespace.MyClass = new MyClass();
One with static vars:
var MyClass = (function(){
var static_var; //static private var
var MyClass = function () {
var privateVar; //private
var privateFn = function(){}; //private
this.someProperty = 5; //public
this.anotherProperty = false; //public
this.someFunction = function () { //public
//do something
};
};
return MyClass;
})();
MyNamespace.MyClass = new MyClass();
With a "constructor" (all of the examples have a "constructor", this one just has parameters to work with):
var MyClass = function (a, b c) {
//DO SOMETHING WITH a, b, c <--
var privateVar; //private
var privateFn = function(){}; //private
this.someProperty = 5; //public
this.anotherProperty = false; //public
this.someFunction = function () { //public
//do something
};
};
MyNamespace.MyClass = new MyClass(1, 3, 4);
With all of the above you can do:
MyNamespace.MyClass.someFunction();
But you cannot do (from the outside):
MyNamespace.MyClass.privateFn(); //ERROR!
Solution 2
The first example is simply an Object literal - it cannot be instantiated and doesn't have private members. The second example has some incorrect syntax (var someProperty: 5
should be var someProperty = 5
) but is using a closure to encapsulate internal private state within a self-invoking anonymous function.
The second approach looks better for encapsulating private members, but could be made more "Object-oriented" by making it an instantiable class:
MyNamespace.MyClass = function() { ... };
MyNamespace.MyClass.prototype.someProperty = 'foo';
Then you can instantiate it with the 'new' keyword:
var aClass = new MyNamespace.MyClass();
aClass.init(...);
Solution 3
I use the following syntax for the instantiable classes with namespace
var MYNamespace = MYNamespace|| {};
MYNamespace.MyFirstClass = function (val) {
this.value = val;
this.getValue = function(){
return this.value;
};
}
var myFirstInstance = new MYNamespace.MyFirstClass(46);
alert(myFirstInstance.getValue());
jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/
Solution 4
Why you should never use
return { methodName : methodDelegate}
like in second example:
MyNamespace.MyClass = (function () {
var someProperty = 5;
var init = function () {
//do something
};
return {
someProperty: someProperty
someFunction: someFunction
};
}());
MyNamespace.MyClass.init();
When you use namespace you have to think about it as about declaration, not the instance.
MyNamespace = {};
MyNamespace.sub = {};
MyNamespace.anotherSub = {};
MyNamespace.sub.MyClass = (function () {
var static_var; //static private var
var MyClass2 = function () {
var privateVar; //private
var privateFn = function () { }; //private
this.someProperty = 5; //public
this.anotherProperty = false; //public
this.someFunction = function () { //public
//do something
};
};
return MyClass2;
})();
debugger;
var c1 = new MyNamespace.sub.MyClass();
c1.someProperty = 1; // creates 5->1.
var c2 = new MyNamespace.sub.MyClass();
c2.someProperty = 2; // creates 5->2. c1 is still 1
debugger;
var myClass = function () {
var someProperty = 5;
var anotherProperty = false;
var init = function () {
//do something
};
var someFunction = function () {
//do something
};
return {
someProperty: someProperty,
anotherProperty: anotherProperty,
init: init,
someFunction: someFunction
};
};
MyNamespace.MyClass = myClass();
var c2 = MyNamespace.MyClass;
// how are planning to create one more object, while it's a reference? copy //the whole one?
c2.someProperty = 2; // changes 5 -> 2
var c3 = MyNamespace.MyClass.init(); // create 2 instead of 5
c3.someProperty = 3; // changes c3 and c3 from 2 to 3.
console.log(c2.someProperty + c3.someProperty);
And no metter how much Module anti-patter was popular. Declaration gives you an ability to use the same code with different instances in an expected way for other developers . The quality of code and simplicity of its reading increases. The goal of any developer is to write a simple code to be read, not a shorter or D.R.Y. - but simple to be read and be understanded by another developer. That decreases the number of bugs first. (c) S. McConnell
Solution 5
How to combine namespace and class declaration:
var ns = { // your namespace
my_value: 1, // a value inside the namespace to avoid polluting
MyClass: function() { // a class inside the namespace
this.class_property: 12,
this.class_method: function() {
console.log("My property: " + this.class_property);
}
},
myFunction: function() { // a function inside a namespace
console.log("I can access namepsace value if you don't use 'new': " + this.my_value);
}
};
Accessing your value:
console.log(ns.my_value);
Now, for the Class and Function: If you use new
, the word this
inside the function will point to it's constructor. If you don't use new
, this
will point to the namespace. So,
Using a Class:
var obj = new ns.MyClass();
Using the Function:
ns.myFunction();
If you construct the object without new
, this
will point to the namespace, so the namespace will be "destroyed" because MyClass.class_property
and MyClass.class_method
will be added to it.
Related videos on Youtube
TruMan1
Updated on July 09, 2022Comments
-
TruMan1 almost 2 years
It seems there are so many ways to set up a JavaScript application so it is confusing as to which one is correct or best. Are there any difference to the below techniques or a better way of doing this?
MyNamespace.MyClass = { someProperty: 5, anotherProperty: false, init: function () { //do initialization }, someFunction: function () { //do something } }; $(function () { MyNamespace.MyClass.init(); });
Another way:
MyNamespace.MyClass = (function () { var someProperty = 5; var anotherProperty = false; var init = function () { //do something }; var someFunction = function () { //do something }; return { someProperty: someProperty anotherProperty: anotherProperty init: init someFunction: someFunction }; }()); MyNamespace.MyClass.init();
The first technique feels more like a class. I am coming from server-side background if this makes a difference. The second technique seems more redundant and a bit awkward, but I see this used a lot too. Can someone please help shed some light and advise the best way to move forward? I want to create a application with lots of classes talking to each other.
-
zzzzBov almost 12 yearsThis isn't using OOP JS so much as using the module pattern.
-
alexp almost 12 yearsAlso, you've implied that the two methods are equivalent, but the second method is not valid. The way you've declared the private variables is syntactically invalid, you just want a regular var statement.
-
TruMan1 almost 12 yearsThx I fixed the second method.
-
thirdender almost 12 yearsIf you're interested in learning more, I would highly recommend Douglas Crockford's Javascript: The Good Parts. He not only offers a Javascript approach to classical OOP, but also explains how Javascript's more LISP-like parts can be used to create some other amazing structures. Starting from the ground-up, he explains how and why each structure works and what works best. Also, you may personally be interested in learning CoffeeScript, especially for its built-in class structure.
-
-
TruMan1 almost 12 yearsHow do I handle the init or a constructor?
-
Naftali almost 12 years@TruMan1 the "constructor" is whatever you pass into the
new MyClass()
. I will add an example with a constructor. -
nnnnnn almost 12 yearsA "constructor" doesn't have to have parameters.
-
Naftali almost 12 years@nnnnnn that is true. I just put it there for flair.
-
Naftali almost 12 years@nnnnnn I added that note to the post.
-
TruMan1 almost 12 yearsHow would I avoid conflicts with another loaded library who creates a "var MyClass" in the global namespace as well? Is there no way around this and have to choose very unique names for my classes like "var TrumanMyClass = function ()..."?
-
Naftali almost 12 yearsOr just name ur class within your namespace ^_^ there is no reason to make it global, I just put it there as an example
-
thomthom almost 11 yearsHow can you define the class directly into the namespace then? I've been struggling with this for a couple of days now - there is clearly something with the design of JavaScript I'm not grasping... :(
-
Admin over 10 yearsLearnt a lot from this answer. Thanks mate.
-
Naftali over 10 yearsHappy to help @DeeMac :-)
-
Sl4rtib4rtf4st almost 4 yearsDoesn't this answer need an update since ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
-
Naftali almost 4 yearsNot that I know of @Sl4rtib4rtf4st -- class is basically syntactic sugar around what exists here.