【问题标题】:Why does JavaScript's eval need parentheses to eval JSON data?为什么 JavaScript 的 eval 需要括号来评估 JSON 数据?
【发布时间】:2009-06-08 11:10:09
【问题描述】:

我已经(艰难地)了解到我需要在 JSON 数据周围添加括号,如下所示:

stuff = eval('(' + data_from_the_wire + ')');
// where data_from_the_wire was, for example {"text": "hello"}

(至少在 Firefox 3 中)。

这背后的原因是什么?我讨厌在不了解幕后内容的情况下编写代码。

【问题讨论】:

  • 我知道您的母语不是英语,但 '(' 和 ')' 是括号。如果您更正此问题,它可能会帮助其他人找到您的帖子。

标签: javascript json eval


【解决方案1】:

eval 接受一系列 Javascript 语句。 Javascript 解析器 将出现在语句中的“{”标记解释为块的开始,而不是对象字面量的开始。

当您将文字括在这样的括号中时:({ data_from_the_wire }) 您正在将 Javascript 解析器切换到表达式解析模式。表达式中的标记“{”表示对象字面量声明的开始,不是块,因此 Javascript 接受它作为对象字面量。

【讨论】:

    【解决方案2】:

    在data_from_the_wire 周围加上括号实际上相当于

    stuff = eval('return ' + data_from_the_wire + ';');
    

    如果您要在不带括号的情况下进行 eval,则将评估代码,如果您在其中确实有任何命名函数,则这些函数将被定义,但不会返回。

    以在创建函数时调用函数的能力为例:

    (function() { alert('whoot'); })()
    

    将调用刚刚定义的函数。但是,以下方法不起作用:

    function() { alert('whoot'); }()
    

    因此我们看到括号有效地将 then 代码转换为返回的表达式,而不仅仅是要运行的代码。

    【讨论】:

    • 第一部分并不完全正确; eval 将字符串解释为顶级代码,因此 return 不起作用。函数的问题类似于原始问题,因为它是函数 statement 和函数 expression 之间的歧义(参见 karim79 的答案)。
    • 我真的认为这个答案是不完整的,为什么 JSON 文字在作为 eval() 的参数时必须用括号括起来。 @karim79 对此的回答更清楚:JSON 文字的 {...} 将被解析为块而不是对象文字(它应该是)。
    【解决方案3】:

    我不确定原因,但我使用来自 json.org 的 the JSON class 解析 JSON。它比使用 eval 安全得多。

    【讨论】:

    • 为什么投反对票?这似乎是一个有效的答案。使用 eval 是不安全的。
    • 他不是在问如何正确使用 eval 来解析 JSON,他是在问为什么需要括号。
    • @TimČas 我意识到我没有直接回答这个问题,但是当有人用枪指着他们的脚并问他们为什么需要移除安全装置时,我首先建议他们用枪指着你的脚可能不是一个好主意。
    • 是的,但如果我问安全气囊是如何工作的,正确的答案是描述它们是如何工作的,而不是说撞车不好:)
    • 这通常是最好的答案。除非您正在处理来自安全来源的大量数据,这些数据被发送到旧浏览器,每 5,000,000 条语句显示错误消息。当 那个 发生时,将漂亮的保险箱 JSON.parse 替换为 eval("(" + response + ")") 是必要的。
    【解决方案4】:

    在 JavaScript 中,大括号用于创建块语句:

    {
    var foo = "bar";
    var blah = "baz";
    doSomething();
    }
    

    上面的行可以放在一个字符串中,evaluated 没有问题。现在考虑一下:

    {
    "foo": "bar",
    "blah": "baz"
    }
    

    大括号导致 JavaScript 引擎认为它是一个组表达式,因此: 字符周围的语法错误。引用MDN...JavaScript Guide...Object Literals:

    您不应该在语句的开头使用对象字面量。 这将导致错误或行为不符合您的预期,因为 { 将被解释为一个块的开始。

    将对象文字包装在() 中的解决方法是告诉引擎将其内容视为表达式,而不是块语句。所以这不起作用:

    ({
    var foo = "bar";
    var blah = "baz";
    doSomething(evil);
    })
    // parse error
    

    但这确实:

    ({
    "foo": "bar",
    "blah": "baz"
    })
    // returns object
    

    【讨论】:

      【解决方案5】:

      发生这种情况是因为没有圆括号 JavaScript 试图将 {"text": ... 解释为 a label 并失败。在控制台试一下,你会得到“invalid label”的错误。

      【讨论】:

        【解决方案6】:

        这实际上取决于data_from_the_wire 的值。在大多数情况下,您的语法是可以的,但是以{ 开头的行被解析为标签,而您的则无效。如果你用括号括起来,它可以防止解析器误解你的表达式。

        只是一个解析问题,真的。使用字符串、数字或函数,您不会有这个问题。

        一种解决方案是始终评估指令而不是表达式。你可以写

        eval('var stuff = {"text": "hello"}');
        

        【讨论】:

          【解决方案7】:

          我不知道,实际上我对这个问题的答案很感兴趣,但我的猜测是,如果没有括号,data_from_the_wire 中的数据将被解释为闭包。也许括号强制评估,因此关联数组被“返回”。

          虽然这种猜测会导致投反对票 =)。

          编辑

          Douglas Crockford 在他的JSON 网站上提到了语法歧义,但这并没有真正帮助我。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-08-09
            • 1970-01-01
            • 2017-11-07
            • 2013-10-05
            • 1970-01-01
            • 2021-06-06
            • 1970-01-01
            • 2015-11-01
            相关资源
            最近更新 更多