JS中Eval解析JSON字符串的一个小问题

作者:异步漫步时间:2026-10-29 22:07:58浏览:505

本文探讨在使用eval()函数解析JSON字符串时,为何必须将字符串包裹在括号内。通过对比直接解析与加括号解析的代码执行结果,解释了JavaScript语法中语句与表达式的区别,以及对象字面量在eval中的特殊处理机制。

JSON解析与eval函数简介

此前曾撰写过关于 JSON 的介绍文章,其中涉及了 JSON 的解析方式。众所周知,在现代浏览器中,可以使用 JSON.parse() API 将 JSON 字符串解析为 JSON 数据对象。而在一些较为陈旧或不够严谨的做法中,开发者可能会选择使用 eval() 函数来实现这一目的。

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相比 XML 更为简洁。由于 JSON 是 JavaScript 的原生格式,因此在 JavaScript 环境中处理 JSON 数据时,无需依赖任何特殊的 API 或第三方工具包。

JSON 的语法规则十分简单:对象被视为无序的“名称/值”对集合。一个对象以左花括号“{”开始,以右花括号“}”结束。每个名称后紧跟一个冒号“:”,而各个“名称/值”对之间则使用逗号“,”进行分隔。


var str = '{"name": "hanzichi", "age": 10}';
var obj = eval('(' + str + ')');
console.log(obj); // Object {name: "hanzichi", age: 10}

eval解析JSON为何需要括号

是否注意到,在向 eval() 传递参数时,str 变量被外层包裹了一层小括号?为什么要采取这种做法?

首先,我们需要了解 eval 函数的定义及其使用场景。

eval() 接收一个字符串作为参数。如果该字符串表示一个表达式,eval() 会对其求值;如果字符串包含一个或多个 JavaScript 声明,eval() 则会执行这些声明。需要注意的是,不应调用 eval() 来为算术表达式求值,因为 JavaScript 引擎会自动处理算术表达式的求值。

简而言之,eval 函数的参数是一个字符串。如果我们将该字符串“去字符串化”(即去除引号并调整内部结构),它通常会转化为一段正常可执行的 JavaScript 代码。

具体如何操作?请看以下示例代码:


var str = "alert('hello world')";
eval(str);

执行上述代码后,会弹出提示框显示“hello world”。我们将 str 变量进行“去字符串化”处理,一种粗暴但直观的做法是去掉外层的引号,并对内部内容进行适当调整(如转义等),从而得到:


alert('hello world')

非常完美!这变成了一段正常的、可执行的 JavaScript 语句。直接运行它即可。

回到最初的问题,为什么 JSON 字符串需要包裹在小括号中?如果不加括号,代码会呈现如下状态:


var str = '{"name": "hanzichi", "age": 10}';
var obj = eval(str); // Uncaught SyntaxError: Unexpected token :

结果报错。为什么会发生错误?让我们尝试将 str 进行“去字符串化”处理后执行看看:


{"name": "hanzichi", "age": 10}; // Uncaught SyntaxError: Unexpected token :

毫无疑问,一个 JSON 对象(或单纯的 JavaScript 对象字面量)本身并不是一个可执行的 JavaScript 语句。等等,让我们尝试以下代码:


var str = '{name: "hanzichi"}';
var obj = eval(str);
console.log(obj); // hanzichi

这又是怎么回事?但如果给 name 属性加上双引号,却又报错了?


var str = '{"name": "hanzichi"}';
var obj = eval(str); // Uncaught SyntaxError: Unexpected token :
console.log(obj); 

令人困惑,其实我们仍可以将 str 进行“去字符串化”处理,看看它是否能成为正确执行的 JavaScript 语句。前者的结果是:


{name: "hanzichi"}

这确实是一条合法的 JavaScript 语句。在 ES6 之前,JavaScript 没有块级作用域的概念,因此 {} 不仅可以在 if、for 等语句中使用,甚至可以在代码的任何位置使用,而不会引起作用域冲突。去掉 {} 后,name: "hanzichi" 依然是一条合法语句,它被称为 label 语句(标签语句)。label 语句在跳出嵌套循环时非常有用,具体可参考 label 相关文档。作为 label 语句的标记,name 不能带有引号,且标记可以放置在 JavaScript 代码的任何位置,即使不使用也无妨。

一旦对象包含两个 key,例如 {name: "hanzichi", age: 10},这就变成了两个 label 语句吗?此时,将 "hanzichi" 和 10 分别视为语句,但语句之间只能使用分号连接(表达式之间才能使用逗号)。因此,修改为以下形式也是可行的:


var str = '{name: "hanzichi"; age: 10}';
var obj = eval(str); 
console.log(obj); // 10

语句与表达式的区别

讨论似乎有些偏离主题,但文章开头代码的错误原因已经找到。为什么加上括号就能解决问题?简单来说,() 会将语句转换为表达式,称为语句表达式。括号内的代码会被转换为表达式进行求值并返回结果,而对象字面量必须作为表达式存在。

本文不会深入探讨表达式理论,关于表达式的详细信息可参考文末链接。值得记住的一点是,表达式永远有一个返回值。大部分表达式会被包裹在 () 内,小括号内不能为空。如果有多个表达式,用逗号隔开,即所谓的逗号表达式,它会返回最后一个表达式的值。

以上所述是小编给大家介绍了JS中Eval解析JSON字符串的一个小问题,希望对大家有所帮助!

作者最新文章