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

eval is evil, but is it flawed?

如果我运行这个:

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

我得到一个错误:

Uncaught SyntaxError: Unexpected token :

让我们手动创建对象:

var foo = {};
foo.ear = {};
foo.ear["<="] = 6;

现在,代码如下:

JSON.stringify(foo)

Returns以下字符串:

'{"ear":{"<=":6}}'

和我开始的一样的字符串(除了白色字符,但那些是无关紧要的),所以eval(JSON.stringify(foo)) returns相同的语法错误错误信息。然而:

$.parseJSON(JSON.stringify(foo))

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

编辑:

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

编辑2:

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

function evalJSON(text) {
    return eval("(" + text + ")");
}

主要 {} 被解析为 block statement

尝试用括号括起来:

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

在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){}
{}

它没有缺陷。要了解正在发生的事情,您需要了解解析器(从左到右)看到了什么样的语句。

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


  1. 你会得到同样的异常,但更简单 {"b":4}。它被解析为 block 内的 "b":4。那是无效的 javascript。没有适合你的 AST 树... 但是,这是由于 {} 语句中的异常所致。那是 BlockStatement。 AST 树:

  2. 一个类似的{b:4}会被理解为b:4,一个有效的js语句——一个blabel for 4... That's parsed as

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


ECMAScript 2015

Blocks:

Block : { StatementList }

eval 本身: Eval 创建一个新的 Realm,它被解析(这里有几个步骤)为 Statement 序列(一个 StatementList),而 this section 又具有 BlockStatement 作为第一选择。这个 必须 { 开头(见上文),所以如果你用括号 (({})) 把它包起来,它 不能 是一个 BlockStatement... 但是如果它匹配为 BlockStatement 必须 是一个 BlockStatement

Expressions 部分的旁注:

An ExpressionStatement cannot start with a U+007B (LEFT CURLY BRACKET) because that might make it ambiguous with a Block

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

var a = {ear: {"<=": 6}};

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

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

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

如果将其放入 eval 语句中,同样适用。