5

Why does the following code needs to add ( and ) for eval?

var strJson = eval("(" + $("#status").val().replace(";","") + ")");

PS: $("#status").val() is returning something like {"10000048":"1","25000175":"2","25000268":"3"};

HoLyVieR
  • 10,985
  • 5
  • 42
  • 67
Ricky
  • 34,377
  • 39
  • 91
  • 131

2 Answers2

4

It depends what the value in that element is (an unknown), wrapping it in () is the safe route to account for possibly of no input being there.

Edit: Now that you've cleared up it's JSON, this isn't valid:

eval('{"10000048":"1","25000175":"2","25000268":"3"}');

But this will result in a valid object being returned:

eval('({"10000048":"1","25000175":"2","25000268":"3"})');
//effectively:
eval('return {"10000048":"1","25000175":"2","25000268":"3"};');

Picture in a JavaScript file:

<script type="text/javascript">
  {"10000048":"1","25000175":"2","25000268":"3"}
</script>

This is going to fail, it's just an object declared inline but not proper syntax...the same reason a server has to support JSONP for it to work.


A bit tangential to the question, but since you're including jQuery, you might as well use $.parseJSON() (which will use the native JSON.parse() if available) for this:

var strJson = $.parseJSON($("#status").val().replace(";",""));
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • Hi the val() returned is something like {"10000048":"1","25000175":"2","25000268":"3"}; – Ricky Sep 29 '10 at 10:01
  • why the first statement is invalid – Ricky Sep 29 '10 at 10:06
  • @Ricky - It's just not valid syntax for the same reason it's not directly in script, since the parser isn't looking at it as an expression whereas adding the `()` effectively is a return statement (since it switches to an expression, recognizing `{` as an object start, getting/returning the object you care about). – Nick Craver Sep 29 '10 at 10:08
3

eval takes a JavaScript statement or expression, but {...} would be valid as a statement or an expression, and the grammar of JavaScript prefers a statement.

As an expression:

{"10000048":"1","25000175":"2","25000268":"3"}

is an Object with some properties (what you want).

As a statement, it is a block:

{                       // begin Block
    "10000048":         // LabelledStatement (but the quotes are invalid)
        "1",            // Expression, calculate string "1" then discard it, then
            "25000175": // you can't put a label inside an expression

which gives an error.

(JavaScript labels can be used to label a particular statement for use with break/continue. They're a bit pointless and almost never used.)

So by adding the parentheses you resolve the ambiguity. Only an expression can start with (, so the contents are parsed in an expression context, giving an object literal, not a statement context.

Incidentally this is not quite enough to correctly interpret all possible JSON values. Due to an oversight in JSON's design, the characters U+2028 and U+2029, two obscure Unicode line-ending characters, are valid to put unescaped in a JSON string literal, but not in a JavaScript string literal. If you want to be safe, you can escape them, eg:

function parseJSON(s) {
    if ('JSON' in window) return JSON.parse(s);
    return eval('('+s.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029')+')');
}
bobince
  • 528,062
  • 107
  • 651
  • 834