eval是邪恶的,但它有缺陷吗?

Laj*_*pad 21 javascript jquery json eval

如果我运行这个:

eval('{ear: {"<=": 6}}');
Run Code Online (Sandbox Code Playgroud)

我收到一个错误:

未捕获的SyntaxError:意外的令牌:

让我们手动创建对象:

var foo = {};
foo.ear = {};
foo.ear["<="] = 6;
Run Code Online (Sandbox Code Playgroud)

现在,以下代码:

JSON.stringify(foo)
Run Code Online (Sandbox Code Playgroud)

返回以下字符串:

'{ "耳朵":{ "<=":6}}'

与我开始使用的字符串相同(除了白色字符,但这些字符不相关),因此eval(JSON.stringify(foo))返回相同的语法错误错误消息.然而:

$.parseJSON(JSON.stringify(foo))
Run Code Online (Sandbox Code Playgroud)

正确执行.这是什么原因?

编辑:

正如nnnnnn和Ron Dadon指出的那样,初始字符串和结果stringify是不同的.但是,正如我在问题中指出的那样,即使stringify用作输入的eval结果也会导致语法错误消息.

EDIT2:

根据所进行的答案和实验,这个功能很有趣:

function evalJSON(text) {
    return eval("(" + text + ")");
}
Run Code Online (Sandbox Code Playgroud)

Yuk*_*élé 16

Main {}被解析为块语句.

尝试用括号括起来:

eval('({ear: {"<=": 6}})');
Run Code Online (Sandbox Code Playgroud)

在javascript {}中可以解析为块或对象

例子:

//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){}
{}
Run Code Online (Sandbox Code Playgroud)


Jan*_*iak 7

它没有缺陷.要了解发生了什么,您需要了解解析器所看到的语句类型(从左到右).

进入它的一个简单方法是使用Javascript AST Visualizer


  1. 你会得到同样的例外,简单得多{"b":4}.它被解析为 "b":4一个块内.这不是有效的JavaScript.没有AST树...但是这是由于{}语句中的异常.那是一个BlockStatement.AST树:{}的AST树

  2. 类似的{b:4}会被理解为b:4,一个有效的js语句-一个b 标签4...这是解析为{b:4}的AST树

  3. 最后,a ({b:4})将被理解为具有b等于的属性的对象声明4.这被解析为AST树({b:4})


ECMAScript 2015

块上:

阻止:{StatementList}

eval本身上:Eval创建一个new Realm,它被解析(这里有几个步骤)作为Statements(a StatementList)的序列,而这个部分BlockStatement作为第一个选项.这必须先从{(见上文),所以如果你有一个支架把它包装(({})),它不能BlockStatement...但如果它匹配BlockStatement必须是一个BlockStatement.

表达式部分的旁注:

ExpressionStatement不能以U + 007B(LEFT CURLY BRACKET)开头,因为这可能会使其与Block不一致

  • 那是因为'b:'是一个标签.该块计算最后一个表达式的值,即4. (5认同)

Ber*_*ard 7

需要评估对象文字符号.分配变量时会发生这种情况:

var a = {ear: {"<=": 6}};
Run Code Online (Sandbox Code Playgroud)

或者当你在它周围放置括号时,一个匿名对象:

({ear: {"<=": 6}});
Run Code Online (Sandbox Code Playgroud)

否则,大括号将被解析为块标记.在您的情况下,这意味着{ear:...}标签定义,标签名为ear.下一个块{"<=": 6}会给您一个语法错误,因为"<=": 6语法无效.

如果将其放入eval声明中,则同样适用.