对setTimeout()第一个参数是字串的深入理解以及eval函数的理解
1 <script language="javascript" type="text/javascript"> 2 var a=1; 3 setTimeout('var a=2;alert(a)', 1000); 4 alert(a); 5 setTimeout('alert(a)',1000); 6 </script>
//1 2 1;
setTimeout的异步我这里就不做过多的解释(异步回调,事件队列相关知识),主要写一下对一个参数是字串的时候注意的地方
从上面的代码中我们可以看出来,setTimeout的第一个参数为字串的时候,其实它相当于new 了一个Function在Function里面去定义的a变量,相当于:
1 <script language="javascript" type="text/javascript"> 2 var a=1; 3 setTimeout(function(){var a=2;alert(a);}, 1000); 4 alert(a); 5 setTimeout(function(){alert(a);},1000); 6 </script> 7 //1 2 1;
1 <script language="javascript" type="text/javascript"> 2 var a=1; 3 (new Function('var a=2;alert(a);')()); 4 alert(a); 5 (new Function('alert(a);')()); 6 </script> 7 //2 1 1
不知道为什么网上太多的人在说setTimeout/setInterval的时候都说污染全局变量,我感觉没污染全局变量啊,只是作用域的问题,就像下面的两个例子
另外我们在使用setTimeout的时候一般还是不要第一个参数传字串:
1 function outer1(){ 2 function inner1(){ 3 setTimeout("inner2()",1000); 4 setTimeout("outer2()",1000); 5 alert("use inner1") 6 } 7 function inner2(){ 8 alert("use inner2") 9 } 10 inner1(); 11 } 12 outer1(); 13 function outer2(){ 14 alert("use outer2") 15 } 16 //use inner1,use outer2
1 function outer1(){ 2 function inner1(){ 3 setTimeout(inner2(),1000); 4 setTimeout(outer2(),1000); 5 alert("use inner1") 6 } 7 function inner2(){ 8 alert("use inner2") 9 } 10 inner1(); 11 } 12 outer1(); 13 function outer2(){ 14 alert("use outer2") 15 } 16 //use inner1,use inner2,use outer2
对于第一个参数传字串来说,会在匿名函数中执行字串内容,这是就只能访问匿名函数体内定义的函数和变量或全局的变量和函数,所以出现了上面的结果。
再看一个例子:
1 function A() { 2 setTimeout("var a=2;alert(a)", 1000); 3 } 4 A(); 5 alert(a);//a is not define 6 ============================================== 7 function A() { 8 setTimeout("var a=2;alert(a)", 1000); 9 alert(a);//a is not define 10 } 11 A(); 12 ============================================ 13 function A() { 14 eval("var a=2;alert(a)", 1000); 15 alert(a);//2 16 } 17 A(); 18 ============================================ 19 function A() {eval("var a=2;alert(a)", 1000);} 20 A(); 21 alert(a);//a is not define 22 ============================================ 23 function A() {window.eval("var a=2;alert(a)", 1000);} 24 A(); 25 alert(a);//2 26 ============================================ 27 function A() {window.eval("var a=2;alert(a)", 1000);alert(a);//a is not define} 28 A();
但是对于eval函数来说就不是这样的了
1 <script language="javascript" type="text/javascript"> 2 var a=1; 3 eval('var a=2;alert(a)'); 4 alert(a); 5 setTimeout('alert(a)',1000); 6 </script>
//2 2 2;
eval函数会把里面的字串直接定义到当前作用域(当前执行的上下文)后面有提到window.eval和eval的区别是window.eval直接定义到作用域链的最顶端window下,不会向setTimeout和new Function那样会在一个闭包函数中去定义,所以eval函数不但会出现xss攻击的危险,还会存在变量污染的问题,所以我们要尽量减少多eval的使用,当有时候万不得已不需用到的时候,我们用new Function去代替eval也是可行的
当让这样也可以:
<script language="javascript" type="text/javascript"> var a=1; (function foo() { eval('var a=2;alert(a);'); })(); alert(a); setTimeout('alert(a)',1000); </script> //2 1 1;
最后还有一个需要注意的地方是:在版本号1.7以上的SpiderMonkey(内置于Firefox,Thunderbird)的实现中(这个是FF的ECMAScript解析引擎,相应的chrome V8,ie的JScript),可以把调用上下文作为第二个参数传递给eval。那么,如果这个上下文存在,就有可能影响“私有”(有人喜欢这样叫它)变量(这一段转自汤姆大叔blog)。
function foo() {
var x = 1;
return function () { alert(x); };
};
var bar = foo();
bar(); // 1
eval('x = 2', bar); // 传入上下文,影响了内部的var x 变量
bar(); // 2
最后一个非常值得注意的地方是eval既是ECMAScript的关键字有时window的一个属性,在运用的时候要注意以下的问题:
1 function test(){ 2 eval('var a=10;') 3 alert(a);//10 4 } 5 test(); 6 -------------------------------------------------------------------- 7 function test(){ 8 eval('var a=10;') 9 } 10 test(); 11 alert(a);//a is not defined 12 -------------------------------------------------------------------- 13 function test(){ 14 window.eval('var a=10;') 15 } 16 test(); 17 alert(a);//10 18 -------------------------------------------------------------------- 19 function test(){ 20 var val=eval; 21 val('var a=10;') 22 } 23 test(); 24 alert(a);//10