How to set up JavaScript namespace and classes properly?

32,750

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.

Share:
32,750

Related videos on Youtube

TruMan1
Author by

TruMan1

Updated on July 09, 2022

Comments

  • TruMan1
    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
      zzzzBov almost 12 years
      This isn't using OOP JS so much as using the module pattern.
    • alexp
      alexp almost 12 years
      Also, 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
      TruMan1 almost 12 years
      Thx I fixed the second method.
    • thirdender
      thirdender almost 12 years
      If 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
    TruMan1 almost 12 years
    How do I handle the init or a constructor?
  • Naftali
    Naftali almost 12 years
    @TruMan1 the "constructor" is whatever you pass into the new MyClass(). I will add an example with a constructor.
  • nnnnnn
    nnnnnn almost 12 years
    A "constructor" doesn't have to have parameters.
  • Naftali
    Naftali almost 12 years
    @nnnnnn that is true. I just put it there for flair.
  • Naftali
    Naftali almost 12 years
    @nnnnnn I added that note to the post.
  • TruMan1
    TruMan1 almost 12 years
    How 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
    Naftali almost 12 years
    Or just name ur class within your namespace ^_^ there is no reason to make it global, I just put it there as an example
  • thomthom
    thomthom almost 11 years
    How 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
    Admin over 10 years
    Learnt a lot from this answer. Thanks mate.
  • Naftali
    Naftali over 10 years
    Happy to help @DeeMac :-)
  • Sl4rtib4rtf4st
    Sl4rtib4rtf4st almost 4 years
    Doesn't this answer need an update since ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • Naftali
    Naftali almost 4 years
    Not that I know of @Sl4rtib4rtf4st -- class is basically syntactic sugar around what exists here.