简体   繁体   中英

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

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

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.

是否可以重构对某些不属于被压缩文件的外部填充函数的 eval 调用?

am i missing something?

var noteval = this.eval; // can be defined before the file is loaded
noteval("alert('not eval. at all');");

(function() {
    console.log(this);
    noteval("alert('chavs!');");
}).bind(window)();

(function() {
    console.log(this);
    noteval("alert('crappy parents');");
}).bind(window.parent)();

check it http://www.jsfiddle.net/nGL79/ with the frames as different eval scopes.

and specific to mootools:

window["ev"+"al"].pass("alert('what');")();
this["ev"+"al"].pass("alert('no!');")(); // local scope too?

and

var noteval = window["ev"+"al"].create({
    bind: this
}); 

hope some of that helps... hope you don't get function eval must be called directly, and not by way of a function of another name though

var e = "e";
window[e+"val"](stuff);

If possible you may want to try one of the other compression libraries since YUI isn't the only game in town anymore.

Here is a couple articles on the other compression tools available.

Microsoft and Google seem to do a better job than YUI anyways.

This way needs jQuery.

function NotEval(code, callBack) {
    $.ajax({
        url: 'data:application/javascript;charset=utf-8,' + encodeURIComponent(code),
        cache:true,
        success: function (r) {
            if (typeof callBack === "function") {
                callBack()
            }
        },
        error: function (r) {
            console.log("Eval error");
            console.log(r)
        }
    })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM