先看例子:
demo1:
var globalVar =123;
function testEval(){
eval(" var globalVar = 'global' ");
}
testEval();
alert(globalVar); //123,ie与ff一样
demo2:
var globalVar =123;
function testEval(){
execScript(" var globalVar = 'global' ");
}
testEval();
alert(globalVar); //IE下globalVar = "global",ff下没有execScript方法
问题来了,eval和execScript在运行的时候变量执作用域不同,execScript又只支持IE。
解决方法:
把“var ”去掉或换成“window.”,这样eval运行过程中声明的变量就在全局域下,但是如果代码来自外部怎么办?
于是想到了
var globalVar =123;
function testEval(){
eval.apply(window,[" var globalVar = 'global' "]);
//eval.call(window," var globalVar = 'global' ");
}
//但是不知道为啥IE不能改变eval执行的环境
testEval();
alert(globalVar);
仔细验证发现,eval中的this也是window,也就是说只是在用var声明变量的时候,处理变量默认作用域的方式不同。后发现不仅在声明变量,使用function关键字声明函数同样存在这个问题。例如:
function testEval(){
window.eval(" function GlobalFun(){ return 'globalFun();';} ");
//window.execScript(" function GlobalFun(){ return 'globalFun();';} ");
//IE可以使用上面的方法,输出globalFun();
}
testEval();
alert(GlobalFun());
使用变量声明函数,不使用var关键字,同样可以解决这个问题:
function testEval(){
window.eval("GlobalFun = function(){ return 'globalFun();';} ");
}
testEval();
alert(GlobalFun());
上面var可以查找替换,function处理起来就比较难了,还要搞个复杂的正则去做转换么,可能是个方法,但不现实。在jQuery中倒是有个解决方案:
// Evalulates a script in a global context
globalEval: function( data ) {
if ( data && rnotwhite.test(data) ) {
// Inspired by code by Andrea Giammarchi
// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
var head = document.getElementsByTagName("head")[0] || document.documentElement,
script = document.createElement("script");
script.type = "text/javascript";
if ( jQuery.support.scriptEval ) {
script.appendChild( document.createTextNode( data ) );
} else {
script.text = data;
}
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709).
head.insertBefore( script, head.firstChild );
head.removeChild( script );
}
},
同样,mootools的源码也有这样一段:
var exec=function(text){
if (!text) return text;
if (window.execScript){
window.execScript(text);
} else {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.text = text;
document.head.appendChild(script);
document.head.removeChild(script);
}
return text;
}
动态插入一个script,并执行代码,然后删除。看来现在解决方法不止一个了,以后使用时多加注意就好了。
至于有人说的“eval和window.eval是不同的”不知道从何说起,至少“window.eval===eval”是成立的;
上面全部代码都在IE8中运行,其他没有注释多个浏览器结果的,就表示还没有详细测试。