window.eval 及相关方法总结

原创 2008年02月26日 18:34:00
本文原发于我在JavaEye上的blog,备份于此。
2月27日更新:
CSDN的人真是的,弄到首页就弄到首页,偏要自作主张改我的标题,加上什么“JScript的window.eval……”,完全牛头不对马嘴(偏偏就是JScript中的window.eval跟eval没有差别)。你好歹要么写“JavaScript”要么写“JS”!唉。。。

前面有帖子说到在函数里如何能在全局空间上eval。 虽然此种需求在绝大多数情况下是不合理的,但是仍有极少数情况可能确实有需要。

JScript有execScript方法可以用来执行脚本。其第一个参数为代码字符串,第二个参数为脚本语言,可以选择jscript或者vbscript。

而在其他脚本引擎中,SpiderMonkey保留了JS最早时候的在对象上的eval方法。也就是在任何对象上,都可以eval,执行时,会把该对象加入scope chain。

例如 {x:1}.eval('x')会返回1,而(o={x:2}).eval('var x = 10')后o.x会等于10。

基本上 o.eval(code); 类似于with (o) { eval(code) }。

唯一值得注意的是var x这样的语句。对于
var o = {x:1};
with(o) {
var x = 2;
}
Safari(JavaScriptCore和KJS引擎)会产生一个全局的x变量。除此之外(JScript、SpiderMonkey、Opera、Rhino等),都会令o.x = 10。注意:前提条件是o上面已经有x属性。

由SpiderMonkey所具有的Object.eval方法,我们可以知道,在Firefox中,window.eval()与直接eval()的效果是不同的。前者的效果接近execScript。

其他引擎不支持Object.eval,但是Opera把window.eval作为一个特例,与Firefox的效果是一样的。除了Safari以外, 我们也可以用with(window) {eval(...)}来模拟execScript,但前提是你知道所有在global上声明的var的名字,并预先在window上创建这些变量——多 数情况下这不太实际。

SpiderMonkey的eval还可以传第二个参数,eval(code, o)基本等价于o.eval(code),但是两者还是有微妙的差别。如
var a = 'global';
var code = 'alert(a)';
var context = (function () { return function a() {} })();
context.eval('alert(a)');
eval('alert(a)', context);
这两次返回的值是不同的。在eval(code, o)的时候,会继续从o.__parent__(即[[scope]])开始寻找。而函数表达式的名字,或者函数外部的with语句,都会给其[[scope]]增加一层对象。

关于new Function(code),实际上PIES就是使用的这个方法来生成代码而不是像其他一些框架那样使用eval。另外我还用它来做对模板的“编译”。 使用Function比eval要好很多。因为它总是在一个新的execution context上,从而避免了许多eval可能出现的bug(早期版本的浏览器经常在某些特殊eval时崩溃)。所以如果需要生成代码,应优先使用new Function。

但是new Function对于需要执行var x=1,把x放到global的需求,是不合适的。虽然这种需求非常罕见(以至于多数情况下这种需求是错误的需求),但因为本文恰恰是说这个问题,因此就略过。

事实上,对于SpiderMonkey和Rhino来说,还有另一个方法,也是推荐的方法,那就是使用Script方法。Script(code)的结果 是一个函数,可以直接调用。例如Script('var a = 1')(),无论在哪里执行,都会在global上产生a变量。实际上Script结果的调用就是对Script.prototype.exec的调用。 Script.exec,基本上是execScript的真正对应。注意,Rhino上必须直接调用而不能用Script(code).exec()调 用。SpiderMonkey上Script.exec可以带有参数,如果带有参数obj,效果就跟eval(code, obj)接近。

好,最后总结一下:

JScript上使用execScript(code)
SpiderMonkey和Rhino上可使用Script(code)()
Opera下使用window.eval(code)

唯一的问题是Safari。实际上window.eval已经被作为一个bug被提交并且fixed了(参考http://trac.webkit.org/projects/webkit/changeset/25535),我们希望下一个版本的Safari应该就可以与Opera一样,使用window.eval了。

eval()、window.eval()和with

eval()和window.eval()都可以用来动态执行javascript代码,能给js编程带来很大的灵活性,两者唯一的差别在于执行上下文不同。可以看到:window.eval()的执行上下文是“...
  • aitangyong
  • aitangyong
  • 2015年11月20日 10:27
  • 1172

eval与window.eval的差别

它们之间有区别吗? 开发过程中似乎很少有人去加个额外的window,觉得多此一举。比如Ajax过程中回调函数解析JSON格式字符串 ? 1 2 3 4 5 ... function...
  • lvjin110
  • lvjin110
  • 2013年09月23日 15:08
  • 1257

js中执行脚本字符串方法:window.eval()/eval()

它们之间有区别吗?开发过程中似乎很少有人去加个额外的window,觉得多此一举。比如ajax过程中回调函数解析json格式字符串:   Js代码   ...  function ...
  • superdog007
  • superdog007
  • 2014年04月17日 16:41
  • 4851

TCP知识点总结

要说计算机网络的重点肯定是TCP/IP协议族了,这两个协议几乎涵盖了整个网络通信的流程。弄清楚客户端和服务器端之间的通信过程,基本上就对TCP/IP掌握的差不多了。所以接下来要开始介绍这篇文章的主角T...
  • slforeverlove
  • slforeverlove
  • 2015年07月23日 10:25
  • 895

mybatis知识点总结和梳理

使用jdbc开发时,和mybatis相比的不足 1,数据库连接,使用时就创建,不使用就释放,对数据库进行频繁连接开关和关闭,造成数据库资源浪费,影响数据库的性能 解决:使用数据库连接池管理数据库的...
  • jaryle
  • jaryle
  • 2016年04月23日 22:28
  • 8203

view类的xml属性、相关方法及说明

View类是所有可视化控件的基类,主要提供了控件绘制和事务处理的方法。创建用户界面所使用的控件都继承自View,如EditText、TextView、Button等。View及其子类的相关属性,既可以...
  • u012587637
  • u012587637
  • 2014年04月08日 11:21
  • 989

采样方法(二)MCMC相关算法介绍及代码实现

0.引子书接前文,在采样方法(一)中我们讲到了拒绝采样、重要性采样一系列的蒙特卡洛采样方法,但这些方法在高维空间时都会遇到一些问题,因为很难找到非常合适的可采样Q分布,同时保证采样效率以及精准度。 ...
  • Dark_Scope
  • Dark_Scope
  • 2017年12月30日 15:32
  • 1292

数组的属性和方法总结

Array()是一个用来创建数组对象的构造器! 定义数组有两种方法: var arr = new Array(1,2,3); var arr1 = [1,2,3] 注意一点的是 第一种写法 如...
  • user_bin
  • user_bin
  • 2017年05月04日 22:01
  • 505

请说出与线程同步以及线程调度相关的方法

-wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁; -sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedExce...
  • u014136713
  • u014136713
  • 2016年05月16日 18:36
  • 2192

App自动化测试工具总结

无线客户端的发展很快,特别针对是android和ios两款无线操作系统的客户端应用,相应的测试工具也应运而生,这里主要给大家介绍一些针对iPhone App的自动化测试工具。   首先,我们把这...
  • sun2728
  • sun2728
  • 2015年06月29日 15:09
  • 2438
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:window.eval 及相关方法总结
举报原因:
原因补充:

(最多只允许输入30个字)