eval解析JSON字符串的一个小问题,函数使用方法
分类:澳门新萄京最大平台

eval解析JSON字符串的一个小问题

2016/02/24 · JavaScript · JSON

原文出处: 韩子迟   

之前写过一篇 关于 JSON 的介绍文章,里面谈到了 JSON 的解析。我们都知道,高级浏览器可以用  JSON.parse() API 将一个 JSON 字符串解析成 JSON 数据,稍微欠妥点的做法,我们可以用 eval() 函数。

JavaScript

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

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

 

是否注意到,向 eval() 传参时,str 变量外裹了一层小括号?为什么要这样做?

我们先来看看 eval 函数的定义以及使用。

eval() 的参数是一个字符串。如果字符串表示了一个表达式,eval() 会对表达式求值。如果参数表示了一个或多个 JavaScript 声明, 那么 eval() 会执行声明。不要调用 eval() 来为算数表达式求值; JavaScript 会自动为算数表达式求值。

简单地说,eval 函数的参数是一个字符串,如果把字符串 “noString” 化处理,那么得到的将是正常的可以运行的 JavaScript 语句。

怎么说?举个栗子,如下代码:

JavaScript

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

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

执行后弹出 “hello world”。我们把 str 变量 “noString” 化,粗暴点的做法就是去掉外面的引号,内部调整(转义等),然后就变成了:

JavaScript

alert('hello world')

1
alert('hello world')

very good!这是正常的可以运行的 JavaScript 语句!运行之!

再回到开始的问题,为什么 JSON 字符串要裹上小括号。如果不加,是这个样子的:

JavaScript

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

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

恩,报错了。为什么会报错?试试把 str “noString” 化,执行一下:

JavaScript

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

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

毫无疑问,一个 JSON 对象或者说是一个对象根本就不是能执行的 JavaScript 语句!等等,试试以下代码:

JavaScript

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

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

这又是什么鬼?但是给 name 加上 “” 又报错?

JavaScript

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

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

好吧,快晕了,其实还是可以将 str “nostring” 化,看看是不是能正确执行的 JavaScript 语句。前者的结果是:

JavaScript

{name: "hanzichi"}

1
{name: "hanzichi"}

这确实是一条合法的 JavaScript 语句。{} 我们不仅能在 if、for 语句等场景使用,甚至可以在任何时候,因为 ES6 之前 JavaScript 只有块级作用域,所以对于作用域什么的并不会有什么冲突。去掉 {} 后 name: "hanzichi"也是合法的语句,一个 label 语句,label 语句在跳出嵌套的循环中非常好用,具体可以参考 label,而作为 label 语句的标记,name 是不能带引号的,标记能放在 JavaScript 代码的任何位置,用不到也没关系。

一旦一个对象有了两个 key,比如 {name: "hanzichi", age: 10} ,ok,两个 label 语句?将 “hanzhichi” 以及 10 分别看做是语句,但是 语句之间只能用封号连接!(表达式之间才能用逗号)。所以改成下面这样也是没有问题的:

JavaScript

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

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

越扯越远,文章开头代码的错误的原因是找到了,为什么套个括号就能解决呢?简单来说,() 会把语句转换成表达式,称为语句表达式。括号里的代码都会被转换为表达式求值并且返回,对象字面量必须作为表达式而存在

本文并不会大谈表达式,关于表达式,可以参考文末链接。值得记住的一点是,表达式永远有一个返回值。大部分表达式会包裹在() 内,小括号内不能为空,如果有多个表达式,用逗号隔开,也就是所谓的逗号表达式,会返回最后一个的值。

说到表达式,不得不提函数表达式,以前翻译过一篇关于立即执行函数表达式的文章,可以参考下,文末。

Read More:

  • [译]JavaScript中:表达式和语句的区别
  • (译)详解javascript立即执行函数表达式(IIFE)
  • 深入探究javascript的 {} 语句块

    1 赞 1 收藏 评论

澳门新萄京 1

我们都知道,高级浏览器可以用 JSON.parse() API 将一个 JSON 字符串解析成 JSON 数据,稍微欠妥点的做法,我们可以用 eval() 函数。

之前写过一篇 关于 JSON 的介绍文章,里面谈到了 JSON 的解析。我们都知道,高级浏览器可以用 JSON.parse() API 将一个 JSON 字符串解析成 JSON 数据,稍微欠妥点的做法,我们可以用eval() 函数。

本教程主要重介绍eval()函数的语法与使用方法,及在后面我还补充了eval()解析json数据的相关例子,希望文章能帮助到各位深入理解eval()使用方法吧。

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

JSON (JavaScript Object Notation)一种简单的数据格式,比xml更轻巧。 JSON 是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON 数据不需要任何特殊的 API 或工具包。

 

澳门新萄京,是否注意到,向 eval() 传参时,str 变量外裹了一层小括号?为什么要这样做?

JSON的规则很简单: 对象是一个无序的“‘名称/值'对”集合。一个对象以“{”结束。每个“名称”后跟一个“:”;“‘名称/值' 对”之间使用“,”分隔

前几天说到js中尽量不要使用eval,但是eval到底是什么那?今天我们就说说eval的那点事。  

我们先来看看 eval 函数的定义以及使用。

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

首先看一下本定义:

eval() 的参数是一个字符串。如果字符串表示了一个表达式,eval() 会对表达式求值。如果参数表示了一个或多个 JavaScript 声明, 那么 eval 来为算数表达式求值; JavaScript 会自动为算数表达式求值。

是否注意到,向 eval() 传参时,str 变量外裹了一层小括号?为什么要这样做?

定义和用法

简单地说,eval 函数的参数是一个字符串,如果把字符串 “noString” 化处理,那么得到的将是正常的可以运行的 JavaScript 语句。

我们先来看看 eval 函数的定义以及使用。

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。

怎么说?举个栗子,如下代码:

eval() 的参数是一个字符串。如果字符串表示了一个表达式,eval() 会对表达式求值。如果参数表示了一个或多个 JavaScript 声明, 那么 eval 来为算数表达式求值; JavaScript 会自动为算数表达式求值。

语法

var str = "alert";eval;

简单地说,eval 函数的参数是一个字符串,如果把字符串 "noString" 化处理,那么得到的将是正常的可以运行的 JavaScript 语句。

eval(string)

执行后弹出 “hello world”。我们把 str 变量 “noString” 化,粗暴点的做法就是去掉外面的引号,内部调整,然后就变成了:

怎么说?举个栗子,如下代码:

 

alert
var str = "alert";eval;

参数

very good!这是正常的可以运行的 JavaScript 语句!运行之!

执行后弹出 "hello world"。我们把 str 变量 "noString" 化,粗暴点的做法就是去掉外面的引号,内部调整,然后就变成了:

描述

再回到开始的问题,为什么 JSON 字符串要裹上小括号。如果不加,是这个样子的:

alert

 

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

very good!这是正常的可以运行的 JavaScript 语句!运行之!

string    必需。要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句。   

恩,报错了。为什么会报错?试试把 str “noString” 化,执行一下:

再回到开始的问题,为什么 JSON 字符串要裹上小括号。如果不加,是这个样子的:

返回值

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

通过计算 string 得到的值(如果有的话)。

毫无疑问,一个 JSON 对象或者说是一个对象根本就不是能执行的 JavaScript 语句!等等,试试以下代码:

恩,报错了。为什么会报错?试试把 str "noString" 化,执行一下:

说明

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

该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。因此请不要为 eval() 函数传递 String 对象来作为参数。

这又是什么鬼?但是给 name 加上 “” 又报错?

毫无疑问,一个 JSON 对象或者说是一个对象根本就不是能执行的 JavaScript 语句!等等,试试以下代码:

如果试图覆盖 eval 属性或把 eval() 方法赋予另一个属性,并通过该属性调用它,则 ECMAScript 实现允许抛出一个 EvalError 异常。

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

抛出

好吧,快晕了,其实还是可以将 str “nostring” 化,看看是不是能正确执行的 JavaScript 语句。前者的结果是:

这又是什么鬼?但是给 name 加上 "" 又报错?

如果参数中没有合法的表达式和语句,则抛出 SyntaxError 异常。

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

如果非法调用 eval(),则抛出 EvalError 异常。

这确实是一条合法的 JavaScript 语句。{} 我们不仅能在 if、for 语句等场景使用,甚至可以在任何时候,因为 ES6 之前 JavaScript 只有块级作用域,所以对于作用域什么的并不会有什么冲突。去掉 {} 后 name: "hanzichi"也是合法的语句,一个 label 语句,label 语句在跳出嵌套的循环中非常好用,具体可以参考 label,而作为 label 语句的标记,name 是不能带引号的,标记能放在 JavaScript 代码的任何位置,用不到也没关系。

好吧,快晕了,其实还是可以将 str "nostring" 化,看看是不是能正确执行的 JavaScript 语句。前者的结果是:

如果传递给 eval() 的 Javascript 代码生成了一个异常,eval() 将把该异常传递给调用者。

一旦一个对象有了两个 key,比如 {name: "hanzichi", age: 10} ,ok,两个 label 语句?将 “hanzhichi” 以及 10 分别看做是语句,但是 语句之间只能用封号连接!。所以改成下面这样也是没有问题的:

{name: "hanzichi"}

提示和注释

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

这确实是一条合法的 JavaScript 语句。{} 我们不仅能在 if、for 语句等场景使用,甚至可以在任何时候,因为 ES6 之前 JavaScript 只有块级作用域,所以对于作用域什么的并不会有什么冲突。去掉 {} 后 name: "hanzichi" 也是合法的语句,一个 label 语句,label 语句在跳出嵌套的循环中非常好用,具体可以参考 label,而作为 label 语句的标记,name 是不能带引号的,标记能放在 JavaScript 代码的任何位置,用不到也没关系。

提示:虽然 eval() 的功能非常强大,但在实际使用中用到它的情况并不多。

越扯越远,文章开头代码的错误的原因是找到了,为什么套个括号就能解决呢?简单来说,() 会把语句转换成表达式,称为语句表达式。括号里的代码都会被转换为表达式求值并且返回,对象字面量必须作为表达式而存在。

一旦一个对象有了两个 key,比如 {name: "hanzichi", age: 10},ok,两个 label 语句?将 "hanzhichi" 以及 10 分别看做是语句,但是 语句之间只能用封号连接!。所以改成下面这样也是没有问题的:

 

本文并不会大谈表达式,值得记住的一点是,表达式永远有一个返回值。大部分表达式会包裹在() 内,小括号内不能为空,如果有多个表达式,用逗号隔开,也就是所谓的逗号表达式,会返回最后一个的值。

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

实例代码:

越扯越远,文章开头代码的错误的原因是找到了,为什么套个括号就能解决呢?简单来说,() 会把语句转换成表达式,称为语句表达式。括号里的代码都会被转换为表达式求值并且返回,对象字面量必须作为表达式而存在。

eval函数接收一个参数s,如果s不是字符串,则直接返回s。否则执行s语句。如果s语句执行结果是一个值,则返回此值,否则返回undefined。 
需要特别注意的是对象声明语法“{}”并不能返回一个值,需要用括号括起来才会返回值,简单示例如下:

本文并不会大谈表达式,关于表达式,可以参考文末链接。值得记住的一点是,表达式永远有一个返回值。大部分表达式会包裹在() 内,小括号内不能为空,如果有多个表达式,用逗号隔开,也就是所谓的逗号表达式,会返回最后一个的值。

 代码如下

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

复制代码

var code1='"a" 2'; //表达式
  
varcode2='{a:2}'; //语句
  
alert(eval(code1)); //->'a2'
  
alert(eval(code2)); //->undefined
  
alert(eval('(' code2 ')')); //->[object Object]

eval函数的特点,它总是在调用它的上下文变量空间(也称为:包,closure)内执行,无论是变量定义还是函数定义都是如此

eval作用域

先看这段代码:

 代码如下

复制代码

var x = 1;
(function () {
    eval('var x = 123;');
})();
console.log(x);

这个代码得到的是 1 而不是 123
如果想让 eval 执行的代码是全局的,那么有几种方法。

 代码如下

复制代码

var x = 1;
(function () {
    window.eval('var x = 123;');
})();
console.log(x);

这个方法标准浏览器都可以得到 123 而IE6-8则依然是 1

相同的例如

 代码如下

复制代码

var arr = [0,0,0,0,0,0];
(function () {
    var arr = [1,1,1,1,1,1];
    var _eval = eval;
    window.eval('arr[0] = 123;');
    eval.call(null, 'arr[1] = 123;');
    _eval('arr[2] = 123;');
    (0,eval)('arr[3] = 123;');
})();
console.log(arr);

0,1 貌似不支持IE8- 2,3 貌似不支持 IE7-
反正归根结底就是兼容性有问题。

不过还在IE下有个 execScript 非常好使。

 代码如下

复制代码

var x = 1;
(function () {
    (!-[1,] ? execScript : eval)('var x = 123;');
})();
console.log(x);

eval不可能在全局空间内执行,这就给开发带来了不少问题,也看到过很多人为此郁闷。 
不过现在偶终于找到了解决办法,嘿嘿,可以同时兼容IE和Firefox,方法如下:

 代码如下

复制代码

var X2={} //my namespace:)
  
X2.Eval=function(code){
  
if(!!(window.attachEvent && !window.opera)){
  
//ie
  
execScript(code);
  
}else{
  
//not ie
  
window.eval(code);
  
}
  
}

现在如果要想在函数内定义全局代码,就可以通过调用X2.eval_r(code)方法。

 代码如下

复制代码

var s='global';
  
function demo3(){
  
X2.Eval('var s="local"');
  
}
  
demo3();
  
alert(s); //->'local'

eval解析json

代码如下:

 代码如下

复制代码

var data=" 

root: 

{name:'1',value:'0'}, 
{name:'6101',value:'北京市'}, 
{name:'6102',value:'天津市'}, 
{name:'6103',value:'上海市'}, 
{name:'6104',value:'重庆市'}, 
{name:'6105',value:'渭南市'}, 
{name:'6106',value:'延安市'}, 
{name:'6107',value:'汉中市'}, 
{name:'6108',value:'榆林市'}, 
{name:'6109',value:'安康市'}, 
{name:'6110',value:'商洛市'} 
]
}"; 

 
 
这里以jquery异步获取的数据类型——json对象和字符串为依据,分别介绍两种方式获取到的结果处理方式。
 
1.对于服务器返回的JSON字符串,如果jquery异步请求没做类型说明,或者以字符串方式接受,那么需要做一次对象化处理,方式不是太麻烦,就是将该字符串放于eval()中执行一次。这种方式也适合以普通javascipt方式获取json对象,以下举例说明:
 
var dataObj=eval("(" data ")");//转换为json对象
 
为什么要 eval这里要添加 “("(" data ")");//”呢?
 
原因在于:eval本身的问题。 由于json是以”{}”的方式来开始以及结束的,在JS中,它会被当成一个语句块来处理,所以必须强制性的将它转换成一种表达式。
 
加上圆括号的目的是迫使eval函数在处理JavaScript代码的时候强制将 括号内的表达式(expression)转化为对象,而不是作为语 句(statement)来执行。举一个例子,例如对象字面量{},如若不加外层的括号,那么eval会将大括号识别为JavaScript代码块的开始 和结束标记,那么{}将会被认为是执行了一句空语句。所以下面两个执行结果是不同的:
 
 代码如下:

 代码如下

复制代码

alert(eval("{}"); // return undefined
alert(eval("({})");// return object[Object]

 
 
对于这种写法,在JS中,可以到处看到。
 
如: (function()) {}();  做闭包操作时等。
 
代码如下:

 代码如下

复制代码

alert(dataObj.root.length);//输出root的子对象数量 
$.each(dataObj.root,fucntion(idx,item){ 
if(idx==0){ 
return true; 

//输出每个root子对象的名称和值 
alert("name:" item.name ",value:" item.value); 
}) 

 
 
注:对于一般的js生成json对象,只需要将$.each()方法替换为for语句即可,其他不变。
 
2.对于服务器返回的JSON字符串,如果jquery异步请求将 type(一般为这个配置属性)设为“json”,或者利 用$.getJSON()方法获得服务器返回,那么就不需要eval()方法了,因为这时候得到的结果已经是json对象了,只需直接调用该对象即可,这 里以$.getJSON方法为例说明数据处理方法: 
 
代码如下:

 代码如下

eval解析JSON字符串的一个小问题,函数使用方法。复制代码

$.getJSON(" 
//此处返回的data已经是json对象 
//以下其他操作同第一种情况 
$.each(data.root,function(idx,item){ 
if(idx==0){ 
return true;//同countinue,返回false同break 

alert("name:" item.name ",value:" item.value); 
}); 
});

 
这里特别需要注意的是方式1中的eval()方法是动态执行其中字符串(可能是js脚本)的,这样很容易会造成系统的安全问题。所以可以采用一些规避了eval()的第三方客户端脚本库,比如JSON in JavaScript就提供了一个不超过3k的脚本库。

*eval执行的常见错误

---源码

 代码如下

复制代码

console.log("Eval Usage");
var str1_err = "function () {console.log('run fun1')};";
try{
    eval(str1_err);
}catch(e){
    console.log(" Error! eval(str1_err)");
    console.log(e.toString());
}
var str1 = "function fun1() {console.log('run fun1')}; fun1();";
eval(str1);

var str2_err = "{name: 'dzh'}";
var result;
try{
    result = eval(str2_err);
    console.log(result.toString());
    console.log("name: " result.name);
}catch(e){
    console.log(" Error! eval(str2_err)");
    console.log(e.toString());
}
str2 = "({name: 'dzh'})";
result = eval(str2);
eval解析JSON字符串的一个小问题,函数使用方法。console.log(result.toString());
console.log("name: " result.name);

---结果

 

Eval Usage
 Error! eval(str1_err)
SyntaxError: Unexpected token (
run fun1
dzh
name: undefined
[object Object]
name: dzh

---分析原因

1)str1_err说明了定义匿名函数导致的报错; 遇到空的'()', 会报错;

2)str2_err说明了对于'{}',引擎解析时会把括号理解为代码块, 而程序原意是一个对象直接量; 所以常用的方式是在'{}'外围加小括号, 那么eval就先执行求值运算, 它就返回对象.

综述, 使用eval时, 要考虑引擎是如何理解传入的字符串代码.

出处:

本文由澳门新萄京发布于澳门新萄京最大平台,转载请注明出处:eval解析JSON字符串的一个小问题,函数使用方法

上一篇:创建对象的方式与后续的二种艺术,面向对象 下一篇:没有了
猜你喜欢
热门排行
精彩图文