views:

1349

answers:

6

I've learned (the hard way) that I need to add parentheses around JSON data, like this:

stuff = eval('(' + data_from_the_wire + ')');
// where data_from_the_wire was, for example {"text": "hello"}

(In Firefox 3, at least).

What's the reason behind this? I hate writing code without understanding what´s behind the hood.

A: 

I don't know, and I am actually interested in the answer to this, but my guess is that without the parentheses the data in data_from_the_wire would be interpreted as a closure. Maybe the parentheses force evaluation and so the associative array is 'returned'.

This is the kind of guessing that leads to downvotes though =).

EDIT

Douglas Crockford mentions a syntax ambiguity on his JSON site but that didn't really help me.

Oliver N.
+6  A: 

I'm not sure of the reason but I parse JSON by using the JSON class from json.org. It's much safer than using eval.

Garry Shutler
Why the downvote?It seems like a valid answer.Using eval is unsafe.
the_drow
+15  A: 

eval accepts a sequence of Javascript statements. The Javascript parser interprets the ‘{’ token, occuring within a statement as the start of a block and not the start of an object literal.

When you enclose your literal into parentheses like this: ({ data_from_the_wire }) you are switching the Javascript parser into expression parsing mode. The token ‘{’ inside an expression means the start of an object literal declaration and not a block, and thus Javascript accepts it as an object literal.

karim79
+14  A: 

It is because, putting the brackets in there effectively creates the statement:

stuff = eval('return ' + data_from_the_wire + ';');

If you were to eval without the parentheses, then the code would be evaluated, and if you did have any named functions inside it those would be defined, but not returned.

Take as an example the ability to call a function just as it han been created:

(function() { alert('whoot'); })()

Will call the function that has just been defined. The following, however, does not work:

function() { alert('whoot'); }()

So we see that the parentheses effectively turn then code into an expression that returns, rather than just code to run.

Kazar
+1 Very clear explanation. Thanks.
Oliver N.
+1 for the same reason as Oliver :)
NixNinja
The first part isn't exactly correct; eval interprets the string as top-level code, so return doesn't work.The issue with functions is similar to original question, because it's an ambiguity between a function *statement* and a function *expression* (see karim79's answer).
Matthew Crumley
I really think this answer is incomplete as to why JSON literal, when being as argument to `eval()`, must be enclosed in parenthesis. @karim79's answer is more clear on this: the JSON literal's `{...}` would be parsed as block but not object literal (which it should be).
bryantsai
A: 

This happens because without round braces JavaScript tries to interpret {"text": ... as a label and fails. Try it in console and you'll get "invalid label" error.

drdaeman
+1  A: 

It depends on the value of data_from_the_wire, actually. In most cases your syntax is ok, but a line that begins with { is parsed as a label, and yours is invalid. If you surround it with parenthesis, it prevents the parser from misinterpreting your expression.

Just a parsing problem, really. With strings, numbers or functions, you wouldn't have that problem.

One solution is to always eval instructions and not expressions. You can write

eval('var stuff = {"text": "hello"}');
Alsciende