Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute "eval" without writing "eval" in JavaScript

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

like image 979
adamJLev Avatar asked Feb 03 '10 20:02

adamJLev


People also ask

What does Eval () do in JavaScript?

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.

Why should I never use Eval ()?

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.

Is it safe to use Eval () in JavaScript to access outer variables?

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.

How do you evaluate an expression in JavaScript?

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.


2 Answers

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.

like image 93
adamJLev Avatar answered Sep 23 '22 07:09

adamJLev


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

like image 27
Miquel Avatar answered Sep 21 '22 07:09

Miquel