Why does JavaScript's eval need parentheses to

2019-01-02 18:18发布

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.

7条回答
后来的你喜欢了谁
2楼-- · 2019-01-02 18:25

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"}');
查看更多
梦寄多情
3楼-- · 2019-01-02 18:30

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
查看更多
有味是清欢
4楼-- · 2019-01-02 18:35

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.

查看更多
其实,你不懂
5楼-- · 2019-01-02 18:39

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.

查看更多
零度萤火
6楼-- · 2019-01-02 18:39

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.

查看更多
看淡一切
7楼-- · 2019-01-02 18:42

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.

查看更多
登录 后发表回答