I could not think of a good way to do this without trashing the global namespace. However, if the window
object is going to be trashed, might as well do it to someone else's.
That someone else, is iframe
. I think this is an interesting approach, and if there are any potential pitfalls please leave a comment and I will try to address them.
Basically what is going to happen is an iframe is going to be created. It will have a script element whose content will be the anonymous function passed. Its scope will be entirely sandboxed, aside from any global variables passed in (and their correlating setters if values need to be returned).
using
function
Type: Function( {settings} )
Allows the use of a localized environment
settings
Type: PlainObject
A set of key/value pairs that configure the environment. There is no error handling at the moment.
lib
Type: PlainObject
This argument should be the library used in the localized global environment.
fn
Type: Function
This will be anonymous function which executes under the local environment.
global
Type: PlainObject
The global argument will allow for communication if required between the localized environment and the outside context. Using a key value pair, the key will be the name made available in the localized environment. The value will either be used (in which case the outside environment's value should be used), or the value will be a setter (in which case the outside environment's value will be updated at the end of the function execution). This is a loosely designed implementation and can be adapted for more situations if desired.
jsFiddle Demo
definition of the using function
function using(args){
var lib = args.lib;
var callback = args.fn;
var global = args.global;
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentWindow.exec = function() {
for(var fn in lib){
this[fn] = lib[fn];
}
for(var val in global){
this[val] = global[val];
}
var scr = document.createElement("script");
scr.innerHTML = "("+callback+")()";
iframe.contentWindow.document.body.appendChild(scr);
};
iframe.contentWindow.exec();
for(var val in global){
if(global[val] instanceof Function)
global[val](iframe.contentWindow[val]);
}
iframe.parentNode.removeChild(iframe);
}
code used in demo
var stooges;
var list = document.querySelectorAll(".hello");//just a set of 5 divs classed as hello with w,o,r,l,d in them respectively
using({
lib: _,
global: {
"stooges":function(val){ stooges = val; },
"list":list
},
fn: function(){
function toUpperCase(x){
return x.toUpperCase();
}
function minSize(len){
return function(str){
return str.length >= len;
}
}
stooges = map(filter(["Larry", "Curly", "Moe"], minSize(4)), toUpperCase);
each(list,function(el){console.log(el.innerHTML);});
}
});
console.log(stooges);