Helpful Information
 
 
Category: Coding tips & tutorials threads
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:


function add(a,b){
if(a && b){
return a + b;
}else{
alert('The parameters needs to be checked');
}
}

Developer B develops the following function:


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:


var globalObject = {};

or


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:


globalObject.twoNumbers = {};

After that he creates a function inside the newly created object:


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:


globalObject.fourNumbers = {};

After that he creates a function inside the newly created object:


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:


globalObject.twoNumbers.add(10,89);

Now the developers who needs to invoke A’s function can call it like the following:


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:


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.

Devolper C does this:


<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:


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'.

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 (http://www.dynamicdrive.com/forums/showthread.php?t=35343) — the code would then have generic definitions in a header file:


var add = Generic.create(function() {
alert("Check parameters to add().");
});

... and developers writing add() functions would specialise on it:


// 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:


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:



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:


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 (http://ajile.iskitz.com/), which has a full-featured implementation of dependencies, loading, namespaces, &c.


Devolper C does this:


<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:

// 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:



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.










privacy (GDPR)