Namespaces, inheritance and dynamic loading in JavaScript
It is said that every job has its tool. Some of them are yet to be created. Just recently I needed the right tool for some job, namely managing namespaces, inheritance and dynamic loading in JavaScript. I believe the trio is intrinsically linked and as such requires just one tool.
I was quite specific about what that tool should allow me to do. I wanted to:
- have namespaces that reflect the structure of my code
- store any values in my namespaces, even primitives
- load a file simply by requesting a namespace
- define dependences between different parts of code within the code itself
- not to worry about including all JavaScript files statically
- have inheritance supported by the namespaces
Sadly, I failed to find such a tool.
Luckily, I have created it and it is pretty hot. It does namespaces, dynamic loading and inheritance. The tool is called wn(), after Webnicer. Here's an overview of the most important things I felt I had to get right.
Namespaces
I have read quite a few articles about implementing namespaces in JavaScript and to be fair I haven't found one that would get it right when it comes to nested namespaces. How so? Imagine you have a namespace:
language-javascript
MyApplication.SomeModule
Now, let's say `SomeModule` represents a constructor function. Then you want to create a child constructor function which inherits after `SomeModule`. Acting innocently and intuitively you would probably create a child namespace for it like so:
```language-javascript
MyApplication.SomeModule.ChildModule
Looks ok but it isn't. ChildModule
just became a property of SomeModule
constructor function! You didn't want that, right? All you wanted was to create a child namespace and not a property of the function you have assigned to the parent namespace.
That approach is fundamentally wrong.
I had to fix it, so the above example works just fine in wn()
. Namespace object is completely separated from the value represented by that namespace. Therefore ChildModule
is a child namespace of SomeModule
and does not become a property of the constructor function stored in SomeModule.
I have included numerous examples of namespace usage on the wn() Wiki, so here is just one to give you an idea of how it works:
// Define SomeModule.
wn('SomeModule', function SomeModule() {});
// Define ChildModule
wn('SomeModule.ChildModule', function ChildModule() {});
// Get SomeModule.
var sm = wn('SomeModule');
console.log(sm); // output: function SomeModule() {}
// ChildModule is not a property of SomeModule!
console.log(sm.ChildModule); // output: undefined
// ChildModule however exists.
var cm = wn('ChildModule');
console.log(cm); // output: function ChildModule() {}
Dynamic loading
The tools I found were pretty fancy but I don't really like a loader to dictate how I should write or organize my code. I believe that the loader should be helping in the background rather than trying to change my coding preferences.
On the other hand, defining dependences between namespaces rather than files is quite tempting. By doing so you can create code which is more reusable and less prone to environmental issues. It should not mean however, that each dynamically loaded files has to define a namespace. That would be just wrong. What if you wanted to load dynamically jQuery from the Google CDN?
Closely related matter is translating namespaces to URLs. Should the namespaces reflect the directory tree or, for example, represent just the filenames? Maybe. There is not one good answer. I believe that decision should be in discretion of the developer and not necessarily the one implementing the loader.
I wanted wn() to help developers do things, not make them do things. Therefore the mapping is up to you, although the default one is included for you convenience. Dynamically loaded files don't have to define namespaces if you don't want them to. And any file can define multiple namespaces if that is your wish. Some other libraries require just one namespace per file.
You can find plenty of examples of dynamic script loading on the wn() Wiki.
Inheritance
The trickiest of them all. JavaScript offers prototypal inheritance however classical inheritance can be implemented. People fight holy wars trying to argue how one is superior to the other and I strongly believe it to be pointless. They would better spend their time watching paint dry.
Both approaches have advantages and both can be used by the same code only for different things.
For main building blocks of my application I would rather use classical inheritance. I would be able to check if an object is derived from certain constructor function or whether that constructor function is present up the inheritance chain (instanceof). When the code grows, type checking becomes priceless ally of code maintainability.
On the other hand prototypal inheritance is much more useful for ad-hoc objects. One of the best examples in my opinion is default values. Imagine parent constructor's prototype with a property defaults pointing to an object with some default values. Now, in the child constructors's prototype we would like to add one more default value. We don't want to recreate the whole object, though. The easiest and cleanest thing to do - use prototypal inheritance on the defaults object.
As wn() is focused on main building blocks of an application, it supports classical inheritance. Being built around namespaces, wn() allows to express inheritance using namespaces as well. Just an extra sugar.
Again, you can find examples of inheritance on the wn() Wiki.
I hope you will find wn() useful. I made every effort to make it easy to use as well as the examples easy to read and understand. Nothing's perfect but you can help improving the library by simply dropping a line.
Thanks for reading.
Jacek