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
你会得到同样的异常,但更简单 {"b":4}
。它被解析为 block 内的 "b":4
。那是无效的 javascript。没有适合你的 AST 树...
但是,这是由于 {}
语句中的异常所致。那是 BlockStatement
。 AST 树:
一个类似的{b:4}
会被理解为b:4
,一个有效的js语句——一个b
label for 4
... That's parsed as
最后,({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
语句中,同样适用。
如果我运行这个:
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
你会得到同样的异常,但更简单
{"b":4}
。它被解析为 block 内的"b":4
。那是无效的 javascript。没有适合你的 AST 树... 但是,这是由于{}
语句中的异常所致。那是BlockStatement
。 AST 树:一个类似的
{b:4}
会被理解为b:4
,一个有效的js语句——一个b
label for4
... That's parsed as最后,
({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
语句中,同样适用。