Why does JavaScript's eval need parentheses to eval JSON data?

13,037

Solution 1

Putting the parentheses around data_from_the_wire is effectively equivalent to

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.

Solution 2

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.

Solution 3

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.

Solution 4

In JavaScript, curly brackets are used to create block statements:

{
var foo = "bar";
var blah = "baz";
doSomething();
}

The above lines can be put inside a string and evaluated without problem. Now consider this:

{
"foo": "bar",
"blah": "baz"
}

The curly brackets cause the JavaScript engine to think it is a group expression, hence the syntax error around the : character. Quote from MDN...JavaScript Guide...Object Literals:

You should not use an object literal at the beginning of a statement. This will lead to an error or not behave as you expect, because the { will be interpreted as the beginning of a block.

The workaround of wrapping the object literal inside () works by telling the engine to treat its contents as an expression, not as a block statement. So this does not work:

({
var foo = "bar";
var blah = "baz";
doSomething(evil);
})
// parse error

But this does:

({
"foo": "bar",
"blah": "baz"
})
// returns object

Solution 5

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.

Share:
13,037
RoFF
Author by

RoFF

Updated on June 25, 2022

Comments

  • RoFF
    RoFF almost 2 years

    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.

  • the_drow
    the_drow almost 15 years
    Why the downvote? It seems like a valid answer. Using eval is unsafe.
  • bryantsai
    bryantsai over 14 years
    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).
  • Tim Čas
    Tim Čas over 12 years
    He's not asking how to use eval properly for parsing JSON, he's asking why there is a need for parenthesis.
  • Garry Shutler
    Garry Shutler over 12 years
    @TimČas I realise I wasn't answering the question directly but when someone points a gun at their foot and asks why they need to remove the safety, I first advise them that pointing a gun at your foot might not be a great idea.
  • Tim Čas
    Tim Čas over 12 years
    Yes, but if I ask how airbags work, the proper answer is describing how they work, not saying that crashing a car is bad :)
  • Chris Pfohl
    Chris Pfohl over 9 years
    This is usually the best answer. Unless you are dealing with a large amount of data from a safe source being sent to an old browser that displays error messages every 5,000,000 statements. When that happens replacing the nice safe JSON.parse with eval("(" + response + ")") is a necessity.
  • Marcelo Scofano Diniz
    Marcelo Scofano Diniz about 5 years
    I too was trying to remove the safety with a gun pointed to my foot, wondering why cars have to have an airbag... I think this answer is worthy. PS: To sustain an opinion we do not necessarily need to be serious. Both above comments made my day.