I had an epiphany when writing a module loader. The trouble is that I didn't want modules to have access or ability to mess with the module loader's local variables. Since I was just calling eval with the text of the module, it had all of this access for reading and writing. Since I don't trust even myself, this was not acceptable. The problem was finding a way to sweep all the names under the carpet.
Here's the trivial solution:
(function () {
/* module loader */
this.require = function (url) {
var require = function (url) {
/* this require is for the module */
};
var text = http.requestText(url);
eval(text);
}
})();
Here's a less naive solution:
var evalModule = function (text, require) {
eval(text);
};
(function () {
this.require = function (url) {
var text = http.requestText(url);
var require = function (url) {};
evalModule(text, require);
};
})()
That solution still leaves evalModule as a variable that the module could potentially supplant. I needed to isolate evalModule. My solution uses a member variable of a jail object which eventually gets populated with the evalModule function without giving the closure access to either jail or itself..
(function () {
var jail = {};
this.require = function (url) {
var text = http.requestText(url);
var require = function (url) {};
evalModule(text, require);
};
return jail;
})().evalModule = function (text, require) {
eval(text);
}
Of course, it's not enough to isolate the module in a closure. I also give it a Module object as its context object.
(function () {
var jail = {};
this.require = function (url) {
var text = http.requestText(url);
var require = function (url) {};
var module = new Module(url);
evalModule.call(module, text, require);
};
return jail;
})().evalModule = function (text, require) {
eval(text);
}
So, modules look like this:
var module = this;
assert(this != window);
with (require('module.js')) {
/* go do stuff without fear of name collisions */
}


1 comment:
If you're looking for JavaScript modules, I used this technique in the Chiron module loader, http://modulesjs.com. You can read the source at https://cixar.com/tracs/javascript/browser/trunk/src/modules.js
Post a Comment