eval的那些事

一、事情起因

在学习javascript的时候遇见eval这个函数,很多javascript的书籍都提醒要慎用这个方法,所以到现在对eval都不是很了解。一直到前几天,在项目有遇到了一个问题,才想到去深入的了解这个javascript中最为强大的方法。

二、eval语法

eval语法其实并不复杂,它接受一个string格式的参数,然后将这个参数交给JS解释器来执行。

例如:

1  var foo = '2 + 3';
2  eval(foo); //5
3  
4 var foo = '"a" + "b"';
5 eval(foo);  //'ab'
6 eval('var a = 1');  //undefined

很显然,这里将字符串解释为javascript代码来执行了,如果这段代码可以计算出一个值,那么就将这个值返回,否则就返回undefined。如果传给eval的参数不是一个字符窜,那么eval会直接将参数输出。例如:

1 eval(2);  //2
2 eval(function(){});  // function(){}

 下面说一个大家都非常熟悉的情况,就是用eval方法来解析JSON字符串。现在通过AJAX从服务器上请求了一段JSON字符串,如:

1 var jsonStr = "{name: 'hupeng',  company: 'AutoNavi'}";

 

通过eval可以将这段JSON字符串解析为对象,这样我们就可以取得其中的数据:

1 eval("(" + jsonStr + ")");

 

 其结果会返回一个对象,包含着name和company属性。但是我们如果不加“()”,会发生什么事情,请看下面这个例子:

1 var jsonStr1 = "{name: 'hupeng'}";
2 eval(jsonStr1);   // "hupeng"
3 
4 var jsonStr2 = "{name: 'hupeng',  company: 'AutoNavi'}";
5 eval(jsonStr2);  // SyntaxError: Unexpected token :

 

为什么第一个没有抛出错误,而第二个却抛出语法错误。这是由“{}”的二义性造成的,众所周知,我们可以使用“{}”来声明对象,也可以用它来创建一个语句块。如果我们不用“()”包裹住JSON字符串,那么eval会认为传进来的是一个语句块。解释器按照语句块来解释这段字符串,由于name: 'hupeng'被认为是一个标签语句,而“,”是不可以出现在标签语句后面的,从而引发了语法错误。这也是第一个没有抛出错误,而返回'hupeng'的原因。加上了“()”,将其转化成了一个表达式,这样就可以得到我们想要的结果。 

再看另外一个例子:

1  function test(){
2      eval("var foo = 1;");
3      alert(foo);
4  }
5  
6  test();  //1
7  alert(foo); //抛出错误:foo undefined

第6行运行了test函数,弹出了1,因为通过eval方法声明了一个变量,并将其值赋为1。而第7行则抛出了一个错误:foo undefined。这说明eval方法创建的变量只存在于test函数的作用域内,在全局作用域内调用就出现了错误。

三、eval作用域

在前一个例子中,我们看到eval方法是存在作用域的,其并不会为动态执行的代码创建新的作用域,而是直接在当前作用域里执行。但是有一个很诡异的事情就是:eval和window.eval并不等同。请看下面两段代码

DEMO_1:

1 var foo = 1;
2 function test(){
3     var foo = 2;
4     eval('foo = 3');
5     return foo;
6 }
7 alert(test());
8 alert(foo);

 

DEMO_2:

1 var foo = 1;
2 function test(){
3     var foo = 2;
4     window.eval('foo = 3');
5     return foo;
6 }
7 alert(test());
8 alert(foo);

 

在chrome,firefox和IE9+中,DEMO_1会先后弹出3,1 。DEMO_2会先后弹出2,3。而IE678则不会对eval和window.eval作出区分,DEMO_1和DEMO_2的结果一样,都先后弹出3,1。

这说明window.eval会把动态执行的代码抛到全局作用域里执行,而eval则只是在当前作用域中执行。

 

 

 

 

 

 

 

 

 

 

 

posted @ 2012-12-16 19:44  Danny.hupeng  Views(495)  Comments(0Edit  收藏  举报