The main idea is that you create an object to act as a namespace and then you make all of your objects and functions and classes (which are really function objects) be properties of this "namespace" object. Here is the approach I've decided to take with the JavaScript project I've been working on. This may not be the best way to do it, but it is what I am trying for now as I learn this.
Global Namespace Object
First, I need to create a global namespace object which should have a unique name. I'll call it
myNamespace
, and here is how it is defined:1 var myNamespace = { 2 namespace : function(name, func) { 3 var parts = name.split("."); 4 var space = this; 5 for (var i in parts) { 6 var part = parts[i]; 7 var next = space[part]; 8 if (!next) next = {}; 9 next.namespace = this.namespace; 10 space[part] = next; 11 space = next; 12 } 13 if (func) { 14 func.call(space); 15 } 16 return space; 17 } 18 };Basically, it is just an object. What it provides is a
namespace
method which takes a dot.separated.namespace and returns the namespace object corresponding to that particular name, creating it if necessary. This means that if I make the call myNamespace.namespace("dot.separated.namespace")
, it will create the objects: myNamespace.dot
, myNamespace.dot.separated
, and myNamespace.dot.separated.namespace
. I've made the decision to make the myNamespace
object implicit and not specified in the namespace parameter call because it seems less redundant. The code that does this is fairly forward and lives in the loop on lines 5-12 and the return statement on line 16.The other thing that I've done is added an optional function parameter to the namespace object which will automatically be called on the newly created namespace (line 14). I will explain the idea through examples.
Using This Namespace Object
The simplest way to use this is to just add your variables to the namespace object. i.e. rather than having code in global namespace like:
var x = 5; function sort(arr) { /* code */ }you do something like:
myNamespace.x = 5; myNamespace.sort = function(arr) { /* code */ }or you can even namespace it further:
myNamespace.namespace("util"); myNamespace.util.sort = function(arr) { /* code */}As you can see, by doing this the only global variable you have created is the
myNamespace
object and everything else is a property of it.So what's with the optional function parameter? It lets you define an entire namespace all at once and even allows the idea of private variables and functions from the Module Pattern. Here's an example:
1 myNamespace.namespace("util.collection", function() { 2 var InternalType = function(){/*class that is only used by this namespace*/} 3 InternalType.prototype.sort = function() { /* code */ } 4 5 var Stack = function() { /* code */ } 6 Stack.prototype.push = function(value) { /* code */} 7 // etc. 8 9 this.Stack = Stack; // make the Stack type public in this namespace 10 });Basically lines 2-8 are the internal namespace definition. Anything that gets added to the
this
variable (like Stack on line 9) become the public part of the namespace. Once we've defined the namespace we can then use the public classes and variables in it.var stack = new myNamespace.util.collection.Stack();And, of course, we can use one namespace in another namespace:
1 myNamespace.namespace("my.app.package1", function() { 2 var Stack = myNamespace.util.collection.Stack; // similar to a java import 3 4 var doSomething = function(x) { 5 var stack = new Stack(); 6 stack.push(x); 7 /* do more stuff */ 8 } 9 10 // define public aspects of this namespace 11 this.doSomething = doSomething; 12 });One thing I want to point out is the
Stack
variable on line 2. Fully qualifying everything makes for unwieldy code which is why Java has import statements and C# has using statements. Since the namespaces and the classes are all really just objects, you can create your own variables with shorter names to refer to the fully qualified object. As long as you do this inside a function (for example the anonymous function being passed to the namespace method), the Stack
variable is not polluting the global namespace.Take Home Message
Make sure you respect the global namespace.
Whether you use the function and internally scoped objects or not, the important thing is that the only variable added to the global namespace is
myNamespace
. As such it is easy to avoid collisions with any other libraries, just change the name "myNamespace" to something that is unique to your code. This allows you to play nice with others and not worry about 3rd party apps messing up your functionality.
1 comment:
html list tag examples
List tag ol tag ul tag nested ordered and unordered lists
Post a Comment