Intro
Namespacejs is a simple and quick function for defining namespaces in Javascript. It can be used in Nodejs or Browsers. It has an intuitive syntax and can be easily added current projects. The whole library is just one function which is under 1KB when minified.
namespace( 'com.userpixel.example1' ).hello = function ( str ) {
return 'Hello ' + str + '!';
}
namespace( 'com.userpixel.example2' ).hello = function ( str ) {
return 'Hej ' + str + '!';
}
com.userpixel.example1.hello( 'world' ); //returns 'Hello world!'
com.userpixel.example2.hello( 'värld' ); //returns 'Hej värld!'
hello( 'world' ); //fails because hello() doesn't exist in the global object. It's in its own namespace.
Which files do I need?
From all files in this repository you only need one to use Namespacejs in production: src -> namespace.js. There is a minified version too. This file contains a single function named namespace(). You can just copy that to your code and use it.
How does it work?
The idea is simple: every namespace is an object. So you can write codes that look like packages in Java. For example:
var hello = com.userpixel.example.hello( 'world' );
The com
object is the only part that is defined in global namespace in order to make that intuitive syntax possible.
The namespace
function returns an object that can directly be used for attaching a function. For example:
namespace( 'com.userpixel.example' ).hello = function ( str ) {
return 'Hello ' + str + '!';
}
The namespace()
function makes sure that org.userpixel.example
is a valid namespace (a series of nested objects with
the correct name).
var org = {
userpixel : {
example : {
hello : function () ( str ) {
return 'Hello ' + str + '!';
}
}
}
}
If any of these objects exist, they will be used instead of creating a new one. Therefore, it is possible to add new functions to an existing namespace. The algorithm for namespace object creation looks something like this:
//assuming that the code is running in the browser, global object is window
org = typeof window.['org'] === 'object' ? org || {}
org.userpixel = typeof org.userpixel === 'object' ? org.userpixel || {}
org.userpisel.test = typeof org.userpixel.test === 'object' ? org.userpixel.test || {}
To put is simply, the task for namespace() function is to make sure this chain of names exists and is comprised of objects. After a call to namespace() function, you can simply use the namespace without needing to call the function again:
namespace( 'com.userpixel.example1' );
com.userpixel.example1.hello = function ( str ) {
return 'Hello ' + str + '!';
}
com.userpixel.example1.bye = function ( str ) {
return 'Goodbye ' + str + '!';
}
com.userpixel.example1.hello( 'Fredrik' ); //returns 'Hello Fredrik!'
com.userpixel.example1.bye( 'Fredrik' ); //returns 'Goodbye Fredrik!'
Of course the actual algorithm is more sophisticated. It parses the string trying to find all the identifiers in the namespace and then creates variables for each of them if necessary. Therefore all the identifiers of the namespace should be valid in Javascript. For example:
namespace( '' ); //valid: returns the global object
namespace( 'a' ); //valid: returns object a in global object
namespace( 'abc.def' );//valid
namespace( '1bc.def' );//invalid: 1bc is not a valid Javascript identifier
namespace( '&' );//invalid id
namespace( '$' );//a valid id but keep in mind that it will replace the global $ with an object if it isn't
namespace( '_abc' );//valid
namespace( 'ABC' );//valid but conventionally it is recommended to write the namespaces all in small letters ie: 'abc'
Note: if any of the names in the object hierarcy exists but isn't an object, it will be replaced silently with an empty object. For example:
namespace( 'com.userpixel.example' ).hello = function ( str ) {
return 'Hello ' + str + '!';
}
namespace( 'com.userpixel.example.hello' ).swedish = function ( str ) {
return 'Hej ' + str + '!';
}
The reason is simple: all the names in the namespace string must be objects. Just like java, a string like
org.userpixel.example.hello
can either be a namespace or a function, not both.
Without using global object
If you don't want to use the global object, you can pass an alternative root object to be used for the namespace.
var app = {};
namespace( 'com.userpixel.example', app );
app.com.userpixel.example.hello = function ( str ) {
return 'Hello ' + str + '!';
}
app.com.userpixel.example.hello( 'world' );//works
com.userpixel.example.hello( 'world' );//throws an exception complaining "com" doesn't exist
Tests
QUnit is used for testing Namespacejs. Please take a look at the test.js file to find out to learn more. You can run the tests in your browser too.