9

Possible Duplicate:
jQuery uses (new Function(“return ” + data))(); instead of eval(data); to parse JSON, why?

Given a string which represents a valid JSON string, is there a difference between these two parsing methods:

var str, obj;

str = '{"prop":"value"}';

// method 1:
obj = eval( '(' + str + ')' );

// method 2:
obj = ( new Function( 'return (' + str + ');' ) )();

I noticed that jQuery uses the second method to parse JSON strings (in environments that lack a built-in JSON parser). I wonder why they don't use the first method. Why create a function object and invoke it when you can just use eval()?

Please close as exact duplicate

Community
  • 1
  • 1
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • @Till My question is not about the general difference between those two, but about the difference when parsing JSON strings... – Šime Vidas Nov 22 '11 at 16:54
  • minor nitpick: jQuery strips the json of whitespace and then just does `new Function('return '+str)`, without the parenthesis. This would make the two options give different results on the empty string. – hugomg Nov 22 '11 at 17:51
  • Related: http://stackoverflow.com/questions/3238842/should-jquerys-parsejson-getjson-methods-be-used , http://stackoverflow.com/questions/2449220/jquery-uses-new-functionreturn-data-instead-of-evaldata-to-parse/2449484#2449484 , http://stackoverflow.com/questions/2449220/jquery-uses-new-functionreturn-data-instead-of-evaldata-to-parse/2449649#2449649 – meder omuraliev Nov 22 '11 at 18:11

3 Answers3

3

eval is executed within the scope it was declared. Function generates a new function object with its own scope and returns a reference to that function which can be called.

Take this example:

var x = 123;
var y;
function TestEval()
{
   var y = 1;
   Function("window.alert('Global x: ' + x);")(); //Prints 123
   Function("window.alert('Local y: ' + y);")(); //Prints undefined

   eval("window.alert('Global x: ' + x);"); //Prints 123
   eval("window.alert('Local y: ' + y);"); //Prints 1
}

TestEval();

The first two Function calls will print 123 (the global value of x) and undefined, the global value of y.

The two eval functions will print 123 and 1 (the local value of y). This is because eval has local access to the closure it's being run within. These behaviors (as well as the fact that eval is completely unreliable and inconsistent across many browsers) could be taken advantage of by the jQuery implementation.

Note: Code above tested in Firefox 8, your mileage may vary :)

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • Not sure how much more secure it is? I could still do `document.location = "evil-url"` right? – Amir Raminfar Nov 22 '11 at 16:50
  • Yea I'd guess the security concerns are a wash. I always thought eval was considered "not-secure" due to possible script-injection attacks - but the same argument could be made for Function as well. – Mike Christensen Nov 22 '11 at 16:52
  • @AmirRaminfar: jQuery validates the JSON to prevent that. – SLaks Nov 22 '11 at 16:52
  • Notice however that I didn't ask what the difference between those two is generally, but in this specific case (parsing JSON strings)... `:)` – Šime Vidas Nov 22 '11 at 16:52
  • Yea I've been digging around and it seems the issue is somewhat of a mess. Different browsers have different eval scoping and behavior, and of course very little of it is documented. My guess is the jQuery guys needed to access the global jQuery object itself and eval was too unreliable to work cross-browser. I think the answer to a lot of these question is "Uhh cuz that's what worked for us dude.." Sorry I can't be more precise. – Mike Christensen Nov 22 '11 at 17:11
  • Here's a fun article: http://blog.rakeshpai.me/2008/10/understanding-eval-scope-spoiler-its.html – Mike Christensen Nov 22 '11 at 17:12
2

Using eval is evil because there can be lots of security holes. You are executing code in global scope. Function takes of this differently by executing in its own scope. But one thing Function does better is performance. Looking at this blog shows that Function is almost 2x faster in FF2.

Edit: I am not sure how much more secure it is when you execute document.location = "bad-url", it would still be executed using Function

Amir Raminfar
  • 33,777
  • 7
  • 93
  • 123
  • `new Function(...)` has exactly the same security holes. – SLaks Nov 22 '11 at 16:52
  • @SLaks thanks. I had suspected that. So I doubt this is for security. – Amir Raminfar Nov 22 '11 at 16:53
  • Your answer is the opposite of Mike Christensen's. Which one is correct? – Matt Greer Nov 22 '11 at 17:15
  • I think we're both correct. I meant an `eval` is run within the current closure (has access to local variables of stuff). I think Amir meant if you declare new variables, they're global. I've tried to clarify my answer a bit. – Mike Christensen Nov 22 '11 at 17:34
  • In my tests, I was unable to create a new global variable with either 'eval' or 'Function'. However, both could modify existing globals. So I think the only real diff is the closure they're run in, which I've shown in my example above. – Mike Christensen Nov 22 '11 at 17:41
0

The global scope thing and also it won't execute anything after a ";" because of the return, that helps a lil bit.

Delta
  • 4,308
  • 2
  • 29
  • 37