with ,eval 已经够麻烦了,被归到 bad parts 后总算减轻点负担,但如果确实使用了 eval,则要考虑下 this 是否受到影响.
this:
在 google 代码规范 中提及到 this 的指向有5种情况:
1.大多数情况指向全局对象,在浏览器环境下就是 window
2.在 eval 中指向 the scope of the caller
3.在 dom1 事件绑定中指向绑定的元素,dom2 标准浏览器也是。
4.在apply,call调用下指向参数
5. 构造器中指向新生成对象
eval :
特别是 2 ,其实这里需要仔细说下,应该不是直接指向调用者所用域,而是和调用者作用域中存在的 this 相同才是。
当在函数中直接 eval 时:
function x(){ eval("console.log(this)"); } x(); x.apply({y:1});
根据规范解释:eval 中的 this 和 caller 调用者的 this 相同,上面即相当于,直接:
function x(){ console.log(this); }
但是有点需要注意的是,当间接使用 eval 时,情况就不一样了 :
var y=eval; function x(){ y("console.log(this)"); } x(); x.apply({y:1});
在 webkit 下 this 都指向全局对象 window,而 firefox 则和直接使用 eval 一样,但同时两者在别名情况下执行代码串都丢失了作用域链的信息(这也正是这种写法的主要应用场景,脱离作用域链 )。
不过 IE 却又和 webkit,firefox 有区别,当使用别名 eval 时,这时和直接使用 eval 完全没有区别,作用域链仍然在,this 依然和调用者保持一致,怪异。
这种情况的解释目前尚未找到正式描述。
建议是不要使用直接别名引用,可以 work around by this :
function foo(v){ eval(v) }
但是这里又有点需要注意的地方,v 参数里面不要再引用到 v,否则引用到自身代码打印出来
function foo(v){ eval(v) } var v=1; //woo! surprise foo("alert(v);");
所以最好还是使用 new Function 来执行吧:
var v=1; new Function("alert(this.v);").call({v:2});
若不使用 call 以及 apply ,this 始终指向 window ,作用域链丢失。
终极混合测试:
终极就要达到茴字有几种写法的效果:
var v='outer_v',foo=eval, foo2=function(v2){ eval(v2); }, x='outer_x'; (function (context,fn) { with (context) { foo2("("+fn+").call(this);"); foo("("+fn+").call(this);"); eval("("+fn+").call(this);"); new Function("("+fn+").call(this);")(); } }).call({x:'this_x'},{ v: 'inner_v' }, function () { alert(v);alert(this.x); });