Namespacing JavaScript
One of the biggest drawbacks in JS is the lack of proper namespaces. Some have long used objects to avoid global pollution, but I think it's possible to go further. That's how I came with those two functions :
bundle = function (name, func) {
var cur = global;
var name_arr = name.split('.');
for (i = 0, ilen = name_arr.length; i != ilen; i++) {
var n = name_arr[i];
cur = cur[n] = cur[n] || {};
}
if (func) func.call(cur);
};
fetch = function(imports, func) {
var ob = {};
var inject_bundle = function (name, ob) {
var name_arr = name.split('.');
var cur = eval(name_arr[0]);
for (i = 1, ilen = name_arr.length - 1; i != ilen; i++) {
var n = name_arr[i];
cur = cur[n];
}
var last = name_arr[name_arr.length - 1];
if (last == '*') for(k in cur) ob[k] = cur[k];
else ob[last] = cur[last];
}
if (typeof imports == 'string') inject_bundle(imports, ob);
else for (k in imports) inject_bundle(imports[k], ob);
return func.call(ob);
};
})(this)
bundle is used to create a new namespace, given as a string. If a function is passed as a second argument, then it is called, bounded to the namespace. For example, one could use the following :
this.bleh = "I'm a turtle !";
});
bundle('net.friggeri.quux', function () {
this.a = 32;
this.b = 52;
});
print(net.friggeri.foo.bar.bleh);
print(net.friggeri.quux.a * net.frigger.quux.b);
You might think (and you'd be right) that having long names can be a pain (I would never use something like net.friggeri.quux.a). However, using the fetch function, you can populate an object with whatever slots in a given namespace. Then, using with, you can emulate some kind of pythonish import statement. An example might be useful at this point:
'net.friggeri.foo.bar',
'net.friggeri.quux.*'
],
function () { with(this) {
print(bar.bleh);
print(a*b);
}})
The code is pretty ugly: I have to use eval at some point to make sure it still works if called in a nested function and I didn't find a way to avoid using with in the function passed to fetch. Of course it's possible to use a this.bar.bleh syntax, but the whole point of fetching the contents of the bundle is to avoid using such long variable names.
If you wish to expand this, or have any suggestions, you're welcome to comment.