Disclaimer: The code mentioned in the question is assumed to be running in the trusted environment (not the browser), and the code itself is trusted. So any security considerations about eval
are not applicable. The main goal of the question is to prevent the pollution of the global scope performed by the eval
.
When using the eval
, then the result of the last expression is considered as the return value of the whole eval
, e.g. result of the eval
-ing of the following code will be the value of the y+2=12
expression.
var res = eval("
var x = 5;
var y = x*2;
y+2;
"); //res = 12
At the same time, if we will wrap such a code into the Function
constructor, then the result will be undefined
var res = (new Function("
var x = 5;
var y = x*2;
y+2;
")).call(); //res=undefined
To fix the last snippet, we need to add explicit return to the last expression:
var res = (new Function("
var x = 5;
var y = x*2;
return y+2; // <------- changes here
")).call(); //res=12
So, the eval
and Function
have the different return semantics.
And I can’t just replace eval
with the Function()
in the legacy code. I will also be forced to change the calling side to add the return
in the code, passed to Function()
.
Is there a way to avoid adding explicit return, so it will be possible to replace eval
with the Function()
in a transparent way (let’s assume that we are not interested in the access to the local scope)?
Or maybe another technique exists, which can provide the equivalent of the eval
which will minimise the risks of the global scope pollution and will provide the same return semantics as the original eval
?
Note: The JS engine used in the system is quite old, so it does not support strict mode
and ES6+ features.
2
Answers
Just return evaled code from Function:
Or as Mike suggested:
Note that for technical correctness, the initial
eval
block you’re showing does not just result in 12, it results in everything you wrote =)eval
is a macro that halts JS execution, subs in the code you give it, executes it, and then resumes regular execution. So in this case the result is two new variablesx
andy
in the same scope thateval
was run in, and the "12" simply comes from the fact that assignments are returning operations.If you don’t want to introduce anything new to your scope, then remember that
eval
is a macro: make it sub in the code you need:And of course, that can take arguments just fine, too:
This will now run an IIFE that does whatever it needs to do, returns 12, and then gets garbage collected.
But of course, and this is the important part: if that’s what you need, then you don’t need to eval anything. You can just write the function and call it with the values you already have. You almost never actually need
eval
, even in Adobe scripts.