“eval()”和“JSON.parse()”技术使用互斥格式。
- 带有“eval()”括号是必需的。
- 禁止使用“JSON.parse()”括号。
请注意,有“stringify()”函数会产生“eval”格式。对于 ajax,您应该只使用 JSON 格式。
虽然“eval”包含了整个 JavaScript 语言,但 JSON 只使用了该语言的一小部分。在 JavaScript 语言中,“eval”必须识别的结构是“块语句”(又名“复合语句”);这是一对或花括号“{}”,里面有一些语句。但是花括号也用于对象字面量的语法中。解释因代码出现的上下文而异。有些东西对您来说可能看起来像一个对象字面量,但“eval”会将它视为复合语句。
在 JavaScript 语言中,对象字面量出现在赋值的右侧。
var myObj = { ...some..code..here... };
对象文字不会自行出现。
{ ...some..code..here... } // this looks like a compound statement
回到 2008 年提出的 OP 最初的问题,他询问为什么“eval()”中出现以下错误:
{ title: "One", key: "1" }
答案是它看起来像一个复合语句。要将其转换为对象,您必须将其放入无法使用复合语句的上下文中。这是通过在它周围加上括号来完成的
( { title: "One", key: "1" } ) // not a compound statment, so must be object literal
OP 还询问为什么类似的声明确实成功评估:
[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]
同样的答案也适用——花括号是在不可能复合语句的上下文中。这是一个数组上下文,“ [...]
”,数组可以包含对象,但不能包含语句。
与“eval()”不同,JSON 的功能非常有限。限制是故意的。JSON 的设计者想要一个极简的 JavaScript 子集,只使用可能出现在赋值右侧的语法。因此,如果您有一些可以正确解析为 JSON 的代码...
var myVar = JSON.parse("...some...code...here...");
...这意味着它也将在分配的右侧合法地解析,就像这样..
var myVar = ...some..code..here... ;
但这不是对 JSON 的唯一限制。JSON的BNF 语言规范非常简单。例如,它不允许使用单引号来表示字符串(就像 JavaScript 和 Perl 那样),并且它没有办法将单个字符表示为一个字节(就像 'C' 那样)。不幸的是,它也不允许注释(这在创建配置文件时非常好)。所有这些限制的好处是解析 JSON 速度很快,并且没有提供代码注入的机会(安全威胁)。
由于这些限制,JSON 不能使用括号。因此,JSON 字符串中的括号是非法字符。
始终使用带有 ajax 的 JSON 格式,原因如下:
- 将为 JSON 配置一个典型的 ajax 管道。
- 使用“eval()”将被批评为安全风险。
作为 ajax 管道的示例,考虑一个涉及 Node 服务器和 jQuery 客户端的程序。客户端程序使用具有表单的 jQuery 调用$.ajax({dataType:'json',...etc.});
。JQuery 创建一个 jqXHR 对象供以后使用,然后打包并发送关联的请求。服务器接受请求,处理它,然后准备响应。服务器程序将调用该方法res.json(data)
来打包并发送响应。回到客户端,jQuery 接受响应,查询相关的 jqXHR 对象,并处理 JSON 格式的数据。这一切都不需要手动数据转换。响应不涉及在 Node 服务器上对 JSON.stringify() 的显式调用,也没有在客户端对 JSON.parse() 的显式调用;这一切都为你处理。
“eval”的使用与代码注入安全风险有关。您可能认为不可能发生这种情况,但黑客可以非常有创意。此外,“eval”对于 Javascript 优化也是有问题的。
如果您发现自己使用了“stringify()”函数,请注意某些具有该名称的函数将创建与“eval”兼容而不与 JSON 兼容的字符串。例如,在 Node 中,以下为您提供了以“eval”兼容格式创建字符串的函数:
var stringify = require('node-stringify'); // generates eval() format
这可能很有用,但除非您有特定需求,否则它可能不是您想要的。