Why Does JavaScript's Eval Need Parentheses to Eval JSON Data

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

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.

Why do we need to add parentheses to eval JSON?

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')+')');
}

Why the open quote and bracket for eval('(' + jsonString+ ')') when parsing json string

The syntax ambiguity to which Crockford refers is that if an open curly brace is not found on expression context, it will be recognized like a block, and not like the start of an object literal.

For example:

{"foo": "bar"} // SyntaxError

Will give you a syntax error, because it will be interpreted as a block, with a string literal "foo", and a unexpected usage of the token :.

On the other hand, the parentheses, formally called the grouping operator, can only evaluate expressions, therefore we will not have any syntax ambiguity because a block can only be expected on a statement context.

({"foo": "bar"})

Edit: @el.pescado makes an interesting question:

Can you explain why eval('{}') is undefined?

ECMAScript describes an internal type to explain the behavior of statements, it's called The Completion Specification Type.

Values of the Completion type are triples of the form of (type, value, target), where type can be normal, break, continue, return, or throw.

value can be any language value or empty, and target any Identifier or empty.

An empty block (the production Block : {}) explicitly returns the following completion:

Return (normal, empty, empty).

The eval function, after executing the code, and exiting the newly created execution context, checks the result completion of the evaluated code, and in the Step 7 we can see that undefined is explicitly returned if the completion type is normal and the completion value is empty:

...

7- If result.type is normal and its completion value is empty, then return the value undefined.

...

json text needs to wrap in parenthesis. why?

From here: http://rayfd.wordpress.com/2007/03/28/why-wont-eval-eval-my-json-or-json-object-object-literal/

"Note that an ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block"

eval is evil, but is it flawed?

Main {} are parsed as block statement.

try to wrap in parenthesis:

eval('({ear: {"<=": 6}})');

In javascript {} can be parsed as a block or an object

examples:

//object
var user = {
name: "John",
age: "32"
};

//block
{
let a = 5;
console.log(a);
}

//object:
var a = {};
console.log({});
return {};
({});

//block:
function(){}
for(k in o){}
{}

Difference between JSON.parse() and eval()

Your problem is that you mixing two unrelated things.

eval() is built-in javascript function, which main purpose is to interpret string of javascript code (thus make potentional security hole)

JSON.parse() function is for parse JSON string. Although very simmilar, do not make mistake, JSON is not Javascript and there are tiny differences. You should not use eval() for parsing JSON

What are the differences between JSON and JavaScript object?

Using eval to evaluate JSON in JavaScript

Json is a subset of javascript. So eval will just turn the json into a js-object (except when the json describes an object, then you need to wrap it in '(' ')'). Wrapping it in [ ] will put the object in an array.

However, if the json source is not from a trusted source, the json could also contain arbitrary code, therefore eval should not be used for this purpose. Use JSON.parse instead, it is much safer an easier to use

var json = JSON.stringify(object);
var array = eval("[" + json + "]"); //array contains one element which is a copy of object. Because json is valid javascript.

I cannot understand the parentheses in this JavaScript statement

In that literal example, they have no purpose, but generally they're for enclosing an expression — specifically, for ensuring that the contents of the parens are read as an expression, not as a statement.

You'll see things like that when people are using eval to deserialize data in JSON format. So for instance, they might receive a string in the form:

var s = '{"go_go": "go"}';

...and use this to deserialize it:

var o = eval('(' + s + ')');

This is an old work-around to certain issues, but you're much better off using a proper JSON parsing library, such as any of the three listed on Crockford's github page. (Crockford being the inventor of JSON.) There's one there which does some regexes to detect various malformed-JSON stuff and then uses eval, and two others that don't use eval at all. (I would never use eval when dealing with JSON from an untrusted source.)

Evil eval + parenthesis sample?

Consider:

eval("({a: 'my great object'}.a);");

and

eval("{a: 'my great object'}.a;");

As already mentioned: the second one is a block of code with label so .a simply doesn't have any sense.

JSON.parse vs. eval()

You are more vulnerable to attacks if using eval: JSON is a subset of Javascript and json.parse just parses JSON whereas eval would leave the door open to all JS expressions.



Related Topics



Leave a reply



Submit