Results 1 to 3 of 3

Thread: JavaScript Namespacing

  1. #1
    Join Date
    Sep 2005
    Location
    India
    Posts
    1,627
    Thanks
    6
    Thanked 107 Times in 107 Posts

    Default JavaScript Namespacing

    Imagine you are working in a multi-developer environment and there are so many JS developers working on the same project. The main issue from a programmer point of view is to maintain the uniquenes of the function names, the variables, objects,etc.

    Consider the following situation in which developer A and B works on the same project. Developer A develops the following function:

    Code:
    function add(a,b){
    	if(a && b){
    		return a + b;
    	}else{
    		alert('The parameters needs to be checked');
    	}
    }
    Developer B develops the following function:

    Code:
    function add(a,b,c,d){
    	if(a && b && c && d){
    		return a + b + c + d;
    	}else{
    		alert('The parameters needs to be checked');
    	}
    }
    Now imagine that the order of the above mentioned function in the JavaScript file is like the way I’ve ordered, first A’s function after that B’s function. From some other point A tries to call his function with two parameters, what would be the result? Interestingly JavaScript will never show any error when have multiple versions of a function with the same name. But it is not as intelligent as C++ to support function overloading in this scenario. JavaScript will simply execute the last defined function, as a result of that the function developer A made will result in an error, it will say that there is some issue in the passed parameters. Life of a JavaScript developer would be a lot better if he can avoid these kind of issues.

    What we need here is some mechanism using which we can minimize the name collision issues. Any one familiar with C++, C# will remember namespaces and especially if they are new in JavaScript development they’ll surely miss that feature too. Namespacing is nothing but compartmentalizing your code in more efficient manner in order to avoid the name collision issues.

    Does JavaScript support namespacing? The answer is no. But we can do this namespacing mechanism using another feature of JavaScript - JavaScript object literals.

    Lets jump into an example

    We declare a empty JavaScript object in the following manner:

    Code:
    var globalObject = {};
    or

    Code:
    var globalObject = new Object();
    Now go back to our previous example in which A and B has developed two functions with the same name but with different functionality. Have a look at A’s function, which works on two numbers. Now assume that instead of creating that function directly in global namespace A decides to create it inside an object, the object denotes, it works on two numbers and he creates something like the following:

    Code:
    globalObject.twoNumbers = {};
    After that he creates a function inside the newly created object:

    Code:
    globalObject.twoNumbers.add = function(a,b){
    	if(a && b){
    		return a + b;
    	}else{
    		alert('The parameters needs to be checked');
    	}
    };
    Now it is B’s turn, check his function that works on four numbers. Like A he creates another object for his purpose in the global object:

    Code:
    globalObject.fourNumbers = {};
    After that he creates a function inside the newly created object:

    Code:
    globalObject.fourNumbers.add = function(a,b,c,d){
    	if(a && b && c && d){
    		return a + b + c + d;
    	}else{
    		alert('The parameters needs to be checked');
    	}
    };
    Now the developers who needs to invoke A’s function can call it like the following:

    Code:
    globalObject.twoNumbers.add(10,89);
    Now the developers who needs to invoke A’s function can call it like the following:

    Code:
    globalObject.fourNumbers.add(13,841,6,98);
    Achieving namespace effect in JavaScript is very simple the only requirement is to understand how the javascript object literal notation works.

    Another example of the above mentioned item in a single step:

    Code:
    var globalObject = {
        twoNumbers: {
            add: function(a, b) {
    
                if (a && b) {
                    return a + b;
                } else {
                    alert('The parameters needs to be checked');
                }
            }
        },
        fourNumbers: {
            add: function(a, b, c, d) {
                if (a && b && c && d) {
                    return a + b + c + d;
                } else {
                    alert('The parameters needs to be checked');
                }
            }
        }
    };
    * This is an exact copy of my article posted in my blog.
    Last edited by codeexploiter; 02-19-2009 at 03:18 AM.

  2. The Following User Says Thank You to codeexploiter For This Useful Post:

    jsnewbie (02-24-2009)

  3. #2
    Join Date
    Jan 2008
    Posts
    4,168
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    Devolper C does this:
    Code:
    <script type="text/javascript">
    Array.prototype.add = function(){
      for(i=0,a=0;i<this.length;i++){
        a += parseInt(this[i]);
      }
      alert(a);
    };
    ['7','2'].add();
    </script>
    (I tried to highlight some of it, I cant right now, to busy)

    In your last code:
    Code:
    var globalObject = {
        twoNumbers: {
            add: function(a, b) {
    
                if (a && b) {
                    return a + b;
                } else {
                    alert('The parameters needs to be checked');
                }
            }
        },
        fourNumbers: {
            add: function(a, b, c, d) {
                if (a && b && c && d) {
                    eturn a + b + c + d;
                } else {
                    alert('The parameters needs to be checked');
                }
            }
        }
    You forgot the 'r'.
    Last edited by Nile; 02-18-2009 at 01:11 PM.
    Jeremy | jfein.net

  4. #3
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    But it is not as intelligent as C++ to support function overloading in this scenario.
    Not out of the box, but it can be implemented — the code would then have generic definitions in a header file:

    Code:
    var add = Generic.create(function() {
        alert("Check parameters to add().");
    });
    ... and developers writing add() functions would specialise on it:

    Code:
    // Developer A, 2005-08-01
    add.specialise(['number', 'number', 'undefined'],
                   function(a, b) { return a + b; });
    
    ...
    
    // Developer B, 2008-05-23
    add.specialise(['number', 'number', 'number', 'number', 'undefined'],
                   function(a, b, c, d) { return a + b + c + d; });
    This way we can also group that error-checking into one place (and end up with much terser code after the sharing).

    Your information is mostly good, but be aware that namespacing objects, like constructor functions, conventionally begin with capital letters:

    Code:
    var GlobalObject = {
        TwoNumbers: {
            add: function(a, b) {
                if (a && b)
                    return a + b;
                else
                    alert('The parameters need to be checked');
            }
        },
    
        FourNumbers: {
            add: function(a, b, c, d) {
                if (a && b && c && d)
                    return a + b + c + d;
                else
                    alert('The parameter needs to be checked');
            }
        }
    };
    Also, I'm not sure if you intended to do this, but your code doesn't allow one to add a zero.

    Of course, this is all for the sake of example: 'GlobalObject' is a stupid name for a namespacing object. Personally I like to arrange things in a Category.func form, e.g. Array.map(). This also gives you compatibility with the Javascript built-in objects, which are arranged like this for non-prototyped properties (Math.round()). If your code is project-specific, it might be worthwhile to use a Project.Category.func format.

    Another handy hint is that you needn't create the object directly. Especially if you have something like:

    Code:
    var GlobalObject = {
        TwoNumbers: {
            add: function(a, b) {
                return a + b;
            }
        },
    
        FourNumbers: {
            add: function(a, b, c, d) {
                return GlobalObject.TwoNumbers.add(a, b) + GlobalObject.TwoNumbers.add(c, d);
            }
        }
    };
    What happens if we decide to move GlobalObject, or rearrange its external structure such that TwoNumbers no longer exists? The code errors out, because GlobalObject.TwoNumbers.add can't be found. Instead, we can write the functions in a closure, and then return them in a generated object. This also allows us to hide functions and variables (preferably, constants) the user doesn't need to know about:

    Code:
    var GlobalObject = (function() {
        function addTwo(a, b) {
            return a + b;
        }
    
        function addFour(a, b, c, d) {
            return addTwo(a, b) + addTwo(c, d);
        }
    
        return {
            // Nobody needs to add two numbers anyway!
            FourNumbers: {
                add: addFour
            }
        };
    })();
    This way, we can move stuff about and rearrange the structure of the returned object, but the internal functions, which access each other via their internal names and therefore don't require the external names at all, will keep working. Additionally, by using function statements rather than function expressions, we've enabled precompilation for those functions and associated names with them for ease of debugging.

    If you're working on a serious project, though, I recommend Ajile, which has a full-featured implementation of dependencies, loading, namespaces, &c.

    Quote Originally Posted by Nile
    Devolper C does this:

    Code:
    <script type="text/javascript">
    Array.prototype.add = function(){
      for(i=0,a=0;i<this.length;i++){
        a += parseInt(this[i]);
      }
      alert(a);
    };
    ['7','2'].add();
    </script>
    Developer C is a very bad developer indeed, and should be given a stern warning. Not only can prototyped functions not be effectively namespaced in JS, but they've scattered single-letter global variables all over their code — and they've used the function with the wrong types! I just know that's going to cause some confusion:
    Code:
    // innocent code by Developer A, in the global scope
    // Tell the user 'hi!' nine times.
    for (var i = 0, n = ['7', '2'].add() /* DevC told me to do this */; i < n; ++i)
        alert('Hi!');
    Want to have a guess at what this code does? (I recommend not trying it in a browser)

    The correct answer was that it alerts 'Hi!' 70 times — royally annoying the poor user, of course. If you said 72 you were pretty close, but you forgot that add() set i to 2 before it exited.

    It looks as though DevC probably wanted to do something like this:

    Code:
    function add(/* x1[, x2[, ... xn]] */) {
        for (var i = 0, t = 0; i < arguments.length; ++i)
            t += arguments[i];
    
        return t;
    }
    The equivalent on an array I would probably call 'sum' (but function sum(arr) { return add.apply(this, arr); }).

    Here endeth the lesson.
    Last edited by Twey; 02-22-2009 at 09:08 PM.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  5. The Following User Says Thank You to Twey For This Useful Post:

    jsnewbie (02-24-2009)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •