I'm not interested in call or apply to change the this
reference. Just for my own interest, I'm playing with an idea for another require technique for javascript that would make for some cleaner definitions, and the goal was to not have to pass arrays or doubly reference module names for my definitions.
I have a sample solution (just a proof of concept) using toString and eval on a function but I'm wondering if there is a safer or more efficient way to do this.
// Sample module libraries (would probably be in their own files)
someModules = {
testModule: {test: function(){console.log("test from someModule")}},
anotherModule: { doStuff: function(){console.log("Doin stuffs!");}}
};
sampleRequire = function() {
// Load the modules
for (var i=arguments.length-2; i>=0; --i){
// Create a local variable reference to the module
eval ('var '+arguments[i]+' = someModules.'+arguments[i].toString());
}
// Redefine the programmer's function so that it has my local vars in its scope
eval("var fn = "+arguments[arguments.length-1]);
return fn;
}
// Main code...
sampleRequire( 'testModule', 'anotherModule',
function(){
testModule.test();
anotherModule.doStuff();
}
)();
Edit:
Pointy made an excellent point that this would completely destroy the main function's scope, which would often times be unacceptable. Ideally I'd like to see the module variables being added to the function's scope without clobbering its other scoped variables (with the exception of the module names--the programmer must know not to use the same name for two things). I'm betting this is probably impossible, but I would still love to see some ideas.
Another goal is to do this flexibly without having to add arguments per module to the main function. Otherwise we're back to square one with CommonJS styles (which I'm not trying to fight, just curious about scope!).
eval
and without rewriting the callback function (e.g. by adding arguments) is by storing the modules into the global scope, or making sure that the callback is defined within the same scope that defines the modules - Benjie 2012-04-05 15:42
arguments
- user123444555621 2012-04-06 08:47
I tend to say "you're doing it wrong". Using undeclared variables is never a good idea, even though you can.
Here's another hack which writes the modules to the global object. However, this may have side effects on the methods called from the main function.
sampleRequire = function() {
var cache = {};
var moduleNames = [].slice.call(arguments);
var fn = moduleNames.pop();
return function () {
var result, name, i;
// export modules to global object
for (i = 0; i < moduleNames.length; i++) {
name = moduleNames[i];
cache[name] = window[name]; // remember old values
window[name] = someModules[name];
}
result = fn.apply(null, arguments);
// restore original global stuff
for (i = 0; i < moduleNames.length; i++) {
name = moduleNames[i];
window[name] = cache[name];
}
return result;
};
}
I also tried some magic with the with
keyword, which was basically made for precisely what you want. However, it looks like it doesn't work without eval
in this case.
I can't think of any other way of doing what you're after. I also suspect this may be one of the few use cases of eval
that is not evil. But do keep in mind that the modules could rely on their scopes and this could break them.
How about something like:
someModules = {
testModule: {test: function(){console.log("test from someModule")}},
anotherModule: { doStuff: function(){console.log("Doin stuffs!");}}
};
function requireModules() {
var all = [];
for (var i = 0, l = arguments.length; i<l; i++) {
all.push(someModules[i]);
}
return all;
}
(function(testModule,anotherModule){
testModule.test();
anotherModule.doStuff();
}).apply(null,requireModules('testModule','anotherModule'));
window
is only the global object in browsers. In Node.js, for example, the global object is global
. In Web workers, the global object is self
- Rob W 2012-04-05 15:33
I'm not interested in call or apply to change the this reference.
I didn't change the this
reference - in fact I maintained it. I was using apply
to call the function with a dynamic number of arguments - Benjie 2012-04-06 08:46
this
in (function(){})()
points to the global object, or undefined
in strict mode. By using apply
, you explicitly set the this
inside the function to the this
outside the function, which might be the global object. So, you did update the this
reference in the function - Rob W 2012-04-06 08:50