eval运行脚本时,变量的作用域

先看例子:

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中运行,其他没有注释多个浏览器结果的,就表示还没有详细测试。

原文地址:https://www.cnblogs.com/ShepherdIsland/p/2148921.html