JavaScript doesn't provide built-in support for namespaces. Every variable is an object property. A global variable is the property of the global object; a variable declared by var is the property of the call object.
Name conflicts arise easily in JavaScript; even in the same js file. For example, one day you wrote a validate function; someday one takes over your code and write another validate function somewhere in the same file.
function validate() {Unfortunately, the later validate function overwrites the previous one. This might cause original features to fail.
// .. do some validation
}
// a long..long program
// someday...someone
function validate() {
// .. do another validation
}
One of the JavaScript namespace strategies, basically, lets the function be the property of an object. Generally, a meaningful name for organization or a department is used to refer to that object. For example:
var openhome = {}; // creat a unique namespaceTo call the validate function, you can do as follow:
function validate() {
// .. do some validation
}
openhome.validate = validate;
openhome.validate();Others might give similar consideration when defining functions. For example, one might define as follows in the same js file.
var caterpillar = {}; // create a unique namespaceTo invoke it, as follows:
function validate() {
// .. do some validation
}
caterpillar.validate = validate;
caterpillar.validate();This way avoids the variable overriding problem. Perhaps the above name conflicts are rare in one js file, this generally happens when two js files come from different origination or programmers.
People from the same organization might use the same name as a namespace. If you write the following in a.js:
var openhome = {}; // create a namespaceAnother writes the following b.js:
function validate() {
// .. do some validation
}
openhome.validate = validate;
var openhome = {}; // create a namespaceWhat happens if one page includes both a.js and b.js? If b.js is included later, openhome.validate is not available. When creating a namespace, you can test the existence of the namespace object; if there's one, use it directly; if not, create a new object as the namespace. For example, a.js may be revised as follows:
function format() {
// .. do some formatting
}
openhome.format = format;
var openhome = openhome || {};Such way; a new object is created only if openhome is undefined. The b.js may be revised in a similar way to avoid the above name conflict.
function validate() {
// .. do some validation
}
openhome.validate = validate;
Avoid using global variables when writing JavaScript. Does the above example have the problem? Yes! There're two global names in the a.js; one is openhome and the other is validate. Remember! When defining a function in the global scope, the function name is a property of the global object. You can revise the code as follows:
var openhome = openhome || {};But, it's not convenient if this function can also be a property of another object. There's a beautiful way to solve this problem. For example:
openhome.validate = function() {
// do some validation
};
var openhome = openhome || {};It seems complex at first glance. We can look at it step by step. First, we write...
(function() {
function validate() {
// do some validation
}
openhome.validate = validate;
// ... other code ...
})();
function() {This is a function literal and no variable refers to it, so there's nothing stepping into the global namespace. Then ...
}
(function() {Parentheses define the order of operations and evaluate the function literal as a function instance. Then...
})
(function() {The final parentheses indicate calling the evaluated function. You can create local functions in the function literal.
})();
var openhome = openhome || {};The validate function doesn't invade the global namespace because it's local. Finally, only the name openhome exists in the global scope. Patterns like this are broadly used in the world of JavaScript; generally used in a js file for module initialization.
(function() {
function validate() { // validate is local
// do some validation
}
openhome.validate = validate;
// ... other code ...
})();
When designing a library, there's one convention if you want to avoid name conflicts from others. For example, if you want to prevent one from overwriting your name global, you can do as follows:
(function(global) {Maybe that is because you're not sure where your anonymous function will be initialized; you want to use the name global but are afraid of being occupied by someone else. If you use the above way in a browser, the real object referred by this will be passed to the parameter global. The parameter global is a local variable so this way avoids name conflicts from other libraries.
var global.openhome = global.openhome || {};
...
})(this);
Even file names suffer from name conflicts. A file name may have an organization-related prefix, such as "openhome.formutil.js", "caterpillar.formutil.js" and so on, to avoid file name conflicts.
Deep namespace hierarchies might also be a problem. For example:
openhome.book.web.some = 'some';Deep namespace hierarchies are not only troublesome but the successive dot operators also have a performance problem. JavaScript has a hard time optimizing successive dot operators. (Statically typed languages, such as Java, can optimize that.) Although you can use with as follows:
openhome.book.web.other = 'other';
openhome.book.web.another = 'another';
with(openhome.book.web) {But it is not recommended; though it eliminates some typing, but with is hard to optimize, and even might be slower. The better way is:
some = 'some';
other = 'other';
another = 'another';
}
var web = openhome.book.web;
web.some = 'some';
web.other = 'other';
web.another = 'another';