Set Variable inside Eval (JavaScript)

2019-05-19 08:52发布

问题:

i'm writing a GreaseMonkey script (using JQuery), and i need some variables that are set by a script in the original page, like this:

<script type="text/javascript"> 
    var rData = {"20982211":[1,0,1],"20981187":[8,0,4]};
</script>

I fetch this element from another page and try to eval it, put strangely this doesn't work:

$.get(link_url, null, function(data) {
   alert("1:" + rData);
   eval($(data).find("script").text());
   alert("2:" + rData);
}

The strange thing is on the firebug console it works (i just tried the eval directly on the targetpage without the .get), when i run the script though it doesn't. It gives me "null" in both alerts.

Any ideas?

回答1:

EcmaScript 5 redefined eval so that it cannot add variable bindings to the enclosing lexical environment.

http://whereswalden.com/2011/01/10/new-es5-strict-mode-support-new-vars-created-by-strict-mode-eval-code-are-local-to-that-code-only/ talks about the problems with eval under ES 3.

Yet at the same time, eval is too powerful. As inline assembly is to C or C++ (at least without the information gcc‘s asm syntax requires), so is eval to JavaScript. In both instances a powerful construct inhibits many optimizations. Even if you don’t care about optimizations or performance, eval‘s ability to introduce and delete bindings makes code that uses it much harder to reason about.

...

eval‘s ability to add bindings is worse. This can make it impossible to say what a name refers to until runtime:

var v;
function test(code)
{
  eval(code);
  return v;
}

Does the v in the return statement mean the global variable? You can’t know without knowing the code eval will compile and run. If that code is "var v = 17;" it refers to a new variable. If that code is "/* psych! */" it refers to the global variable. eval in a function will deoptimize any name in that function which refers to a variable in an enclosing scope. (And don’t forget that the name test itself is in an enclosing scope: if the function returned test instead of v, you couldn’t say whether that test referred to the enclosing function or to a new variable without knowing code.)

One possible solution to your problem is to use a different evaluation construct, e.g. (new Function('alert(rData); ' + ... + '; alert(rData);')) introduces a complete lexical environment.