2007-09-24
window.eval 及相关方法总结
关键字: eval execScript Script.exec
前面有帖子说到在函数里如何能在全局空间上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了。
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了。
- 10:07
- 浏览 (2389)
- 评论 (4)
- 分类: JS
- 进入论坛
- 发布在 javascript研究小组 圈子
- 相关推荐
评论
robbin
2007-11-02
编辑器的问题修改起来在2.0的代码上面修改起来异常麻烦,但是3.0完全重写的代码已经解决了bug和浏览器兼容性问题。
BTW:我用的也是Opera
BTW:我用的也是Opera
louisling
2007-11-02
对啊, 希望 Robbin 能够看到就好!
hax
2007-09-24
正文更新完毕。
BTW,javaeye目前的编辑器在Opera下会使用WYSIWYG的编辑器,但是又不能正确的显示出来,算是个较严重的bug了。
BTW,javaeye目前的编辑器在Opera下会使用WYSIWYG的编辑器,但是又不能正确的显示出来,算是个较严重的bug了。
afcn0
2007-09-24
不用那么麻烦,eval的context是保存的外面function的context,只要外面是window级别的就可以了
>>> function a(){var b=123;c=function(a){return eval(a)}}
>>> a()
>>> c("b")
123
>>> function a(){var b=123;c=new Function("a","return eval(a)")}
>>> a()
>>> c
anonymous(a)
>>> c("b")
b is not defined
[Break on this error] undefined
javascript: with ... (line 1)
>>> var b=234
>>> c("b")
234
先头的c是a里面的function,所以eval的scope是先c再a再window,第二次是用new Function所以直接把c弄到window下面,所以c的eval是先c再window,和a没关系了,execScript可能和这种new Function一样吧,不会产生scope链吧,并且好似execScript没有返回值
var b=234;
function a(){var b=123;c=function(a){return execScript(a)}}
a();
alert(c("alert(b);b"))
>>> function a(){var b=123;c=function(a){return eval(a)}}
>>> a()
>>> c("b")
123
>>> function a(){var b=123;c=new Function("a","return eval(a)")}
>>> a()
>>> c
anonymous(a)
>>> c("b")
b is not defined
[Break on this error] undefined
javascript: with ... (line 1)
>>> var b=234
>>> c("b")
234
先头的c是a里面的function,所以eval的scope是先c再a再window,第二次是用new Function所以直接把c弄到window下面,所以c的eval是先c再window,和a没关系了,execScript可能和这种new Function一样吧,不会产生scope链吧,并且好似execScript没有返回值
var b=234;
function a(){var b=123;c=function(a){return execScript(a)}}
a();
alert(c("alert(b);b"))
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 139361 次
- 性别:

- 来自: 上海

- 详细资料
搜索本博客
最近加入圈子
最新评论
-
一个嵌入式HTML引擎
这个引擎的源码在什么地方可以下阿
-- by lizhaosuper -
注册Facebook的一点点用户 ...
注册验证码确实有点变态。好在只是一次性的。我经常看到一些网站每次留言都要验证码, ...
-- by hax -
注册Facebook的一点点用户 ...
那个注册验证码太强了点
-- by jinhao7773 -
注册Facebook的一点点用户 ...
第一次使用facebook也发现了这点。他的工作很细致。
-- by wutao8818 -
向左转?向右转?
这个论坛有人发过了
-- by lonelyblue






评论排行榜