Here's the deal, we have a big JS library that we want to compress, but YUI compressor doesn't fully compress the code if it finds an "eval" statement, out of fear that it will break something else. That's great and all, but we know exactly what is getting eval'd, so we don't want it to get conservative because there's an eval statement in MooTools JSON.decode
So basically the question is, is there any alternative (maybe creative) way of writing a expression that returns the eval function? I tried a few, but no dice:
window['eval'](stuff);
window['e'+'val'](stuff);
// stuff runs in the global scope, we need local scope
this['eval'](stuff);
// this.eval is not a function
(new Function( "with(this) { return " + '(' + stuff + ')' + "}"))()
// global scope again
Any ideas? Thx
eval () is a function property of the global object. The argument of the eval () function is a string. If the string represents an expression, eval () evaluates the expression. If the argument represents one or more JavaScript statements, eval () evaluates the statements.
Never use eval ()! eval () is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval () with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension.
Please note that its ability to access outer variables has side-effects. Code minifiers (tools used before JS gets to production, to compress it) rename local variables into shorter ones (like a, b etc) to make the code smaller. That’s usually safe, but not if eval is used, as local variables may be accessed from eval’ed code string.
The argument of the eval () function is a string. If the string represents an expression, eval () evaluates the expression. If the argument represents one or more JavaScript statements, eval () evaluates the statements. We do not call eval () to evaluate an arithmetic expression; JavaScript evaluates arithmetic expressions automatically.
Thanks for all the ideas, I ended up just doing text replacement in the build script that outputs the JS, basically replacing $EVAL$ with eval, after everything has been compressed. I was hoping for a purely JS way, but with so many different eval browser implementations, it's probably better to just leave eval alone
But based on Dimitar's answer and some fiddling around, here's what I found. Seems like the reason why this['eval'] wasn't work is because the place where it's happening, in MooTools JSON.decode, is also a inside a Hash:
var JSON = new Hash({
// snip snip
decode: function(string, secure) {
if ($type(string) != 'string' || !string.length) return null;
if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
return this.eval('(' + string + ')'); // Firefox says: TypeError: this.eval is not a function
}
});
However, if I store the "top level" local scope (all the code, including mootools, runs inside an anonymous function), then it works:
var TOP = this;
var JSON = new Hash({
// snip snip
decode: function(string, secure) {
if ($type(string) != 'string' || !string.length) return null;
if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
return TOP.eval('(' + string + ')'); // All good, things run within the desired scope.
}
});
However this doesn't work in Safari, so bottom line is, what I was trying to do can't be done cross-compatibly. eval is a special touchy function and every browser treats it differently.
Not sure if I understood you, but you can apply a function to a specific local (this) scope:
var x = 5;
var f = new Function('alert(this.x)');
function A(x){
this.x = x;
f.apply(this,[]);
}
a = new A(10);
This alerts 10 as f is applied with A.this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With