【问题标题】:eval is evil, but is it flawed? [duplicate]eval 是邪恶的,但它有缺陷吗? [复制]
【发布时间】:2016-02-18 12:43:03
【问题描述】:

如果我运行这个:

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

我收到一个错误:

Uncaught SyntaxError: Unexpected token :

让我们手动创建对象:

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

现在,下面的代码:

JSON.stringify(foo)

返回以下字符串:

'{"ear":{"

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

$.parseJSON(JSON.stringify(foo))

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

编辑:

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

EDIT2:

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

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

【问题讨论】:

  • JSON.stringify not 返回与第一行相同的字符串。 (您的第一行不是有效的 JSON,因为第一个键名没有被引用。)您是否尝试过将第一行的结果分配给变量? var x = eval(...)
  • 那是因为eval 尝试使用指令块。您没有定义对象。或者 nnnnn 都是对的。
  • 不一样 - 注意 JSON.stringify 中“ear”周围的引号
  • 我认为您对 eval() 的作用感到困惑。它尝试创建 Javascript 块,而不是 JSON。像eval('{var ear ={"&lt;=":6}}'); 这样的东西可以工作。
  • 如果您能弄清楚为什么以下变体 给出错误,则可以加分:eval('{ear: {nose: 6}}')(如果您需要提示,请告诉我。)

标签: javascript jquery json eval


【解决方案1】:

{} 被解析为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){}
{}

【讨论】:

  • 非常有趣。你能告诉我为什么 main {} 被解析为块作用域吗?为什么它被解析为括号内的对象?您是否建议这是对运营商普遍可用的黑客攻击?
  • 出于同样的原因,您也需要将这些自调用匿名函数包装在括号中。
  • @Thilo,我的评论对吗?如果我的评论正确,那么您的回答肯定是正确的。如果不是,你能解释一下为什么我的评论有误吗?
【解决方案2】:

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

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

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

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

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

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

【讨论】:

    【解决方案3】:

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

    一个简单的方法是玩Javascript AST Visualizer


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

    2. 类似的{b:4}会被理解为b:4,一个有效的js语句——blabel对应4...解析为

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


    ECMAScript 2015

    Blocks:

    块:{ StatementList }

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

    Expressions 部分的旁注:

    ExpressionStatement 不能以 U+007B(左大括号)开头,因为这可能会使它与 Block 混淆

    【讨论】:

    猜你喜欢
    • 2013-08-18
    • 2011-04-28
    • 1970-01-01
    • 2012-01-23
    • 2012-10-20
    • 2011-02-04
    • 2011-01-02
    • 2016-11-18
    相关资源
    最近更新 更多