Reputation: 26939
I doubt this is possible, but I'd like to give it a shot.
I'd like write a function that introduces new variables into the scope of its caller.
The goal is to do something like this:
(function() {
var x = {a: 5, b:6};
console.log(typeof a, typeof b); // prints: undefined undefined
magicImport(x);
console.log(a, b); // prints: 5 6
})();
// Variables are not in global scope
console.log(typeof a, typeof b); // prints: undefined undefined
If magicImport(x)
does something like
eval("var a = x.a; var b = x.b;");
that doesn't really help, since the scope of a
and b
will be limited to inside magicImport
.
And of course
eval("a = x.a; b = x.b;");
is no good since that will modify the global object.
Is there any way to eval
code within a higher scope?
EDIT: The goal, in case it isn't clear, is to create function that can import the contents of a namespace without polluting the global scope, and without necessarily having to place those imported objects into a new container object.
Upvotes: 3
Views: 575
Reputation: 42099
As you noted, you'd need to eval, but you have to eval in the scope that they need to be define. There is no way to postpone calling the eval. magicImport has to build the string to be eval'd:
(function() {
var x = {a: 5, b:6};
console.log(typeof a, typeof b); // output: undefined undefined
eval(magicImport(x));
console.log(a, b); // output: 5 6
})();
// Variables are not in global scope
console.log(typeof a, typeof b); // output: undefined undefined
function magicImport(x){
return "var a=" + x.a + ",b=" + x.b ;
}
An alternative would be to skip the function call and use a loop. Instead of eval(magicImport(x));
you could replace it with:
for(prop in x){eval("var " + prop + "=" + x[prop]);}
or
var str = "";
for(prop in x){str + = "var " + prop + "=" + x[prop] + ";" ;}
eval(str);
Upvotes: 1
Reputation: 1577
This isn't much about scopes; you are trying to copy properties into variables which happen to have the same name.
Nevertheless, here's my shot at it:
function magicImport(o) {
for(property in o) {
window[property] = o[property];
}
}
Upvotes: 0
Reputation: 413720
I very strongly suspect that what you want to do is impossible in JavaScript. There's not even a way to refer to enclosing scopes.
I'm not a programming language theorist, but I've written a lot of software. Something about this concept just screams "bad idea" to me. Having functions introduce new symbols willy-nilly would be pretty weird, and it would make it very hard to understand a program.
It's hard to see why what you want to do is better than simply having the caller pick where to store a value. Perhaps features like multi-assignment would make you happier:
var x = { a: null, b: null };
// made up syntax here
<< x.a, x.b >> = magicFunction();
where "magicFunction" would somehow return two values. But because Javascript already has an object notation, that doesn't seem too compelling to me.
Upvotes: 1
Reputation: 46745
Don't do this. Unless you want to end up in a maintainance nightmare.
If I call a function I want to know what side effects it has, what if the the imported stuff changes? I will break everything. I can hardly imagine any need for such magic driven, unmaintainable code, if you really need to import stuff, return a object and use its properties, but don't do scoping magic, since this won't work with closures or other good features of the language.
Upvotes: 3
Reputation: 235992
I'm not sure if this is what you want, but you could just use the with
statement:
function() {
var x = {a: 5, b:6};
console.log(typeof a, typeof b); // prints: undefined undefined
with(x) {
console.log(a, b); // prints: 5 6
}
}
Anyway, since this will modify the such called scope chain (pushing all propertys upfront), any other call within a with
statement will become slower. This is one reason why it's not recommendable to use it. (deprecated in ES5 ES5 strict-mode anyway)
Upvotes: 2