最新下载
热门教程
- 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 
ECMA-262标准的JS里,eval和window.eval的区别
时间:2022-11-14 22:02:53 编辑:袖梨 来源:一聚教程网
看似很简单,运行也正确。eval声明的a只有内部可见;window.eval声明的b全局可见。
| 代码如下 | 复制代码 | 
不过事后回想起来感觉有些诡异。eval和window.eval不就同个函数吗,为什么加上window.意义就不同了呢?如果说eval内部判断了当前this,那么eval和window.eval执行时,this都是指向window。
如果用变量p=window.eval,那么p()和window.eval()还一样吗?
| 代码如下 | 复制代码 | 
经测试,p()和window.eval()的效果完全一样,都是在全局执行。并且p === window.eval 和 p === eval 同时成立!这显然很奇怪,不过还有更奇怪的事在后面!如果我们用q=eval,结果完全出人意料:
| 代码如下 | 复制代码 | 
居然显示的都是number!也就是说指向eval的p,实际效果却是window.eval。他们都是在全局执行代码!
为了验证是否是引用上的区别,我们再做一次测试:
| 代码如下 | 复制代码 | 
明显,eval执行的a被留在了内部,而q=eval的b却是全局的!
于是我推测,标准JavaScript下的eval,也许和this一样,既是关键字,也是一个变量(函数变量)。如果是当关键字调用的话,即字面上的eval(),那么在当前的上下文里执行;否则,即通过变量引用调用的话,就在全局上执行。这样就可以解释 window.eval 和 eval 的区别了:window.eval仅仅是window对象里的一个叫eval的属性,一个指向eval函数的属性。和window.eval2,window.eval3一样,仅仅一个属性,并非字面上的eval。
为了验证这个猜测,我查看了 FireFox 的脚本引擎源码。其中eval真正的执行部分定义在 jsobj.cpp 中的 EvalKernel 里:
| 代码如下 | 复制代码 | 
| 
 bool     /*     } else {         JS_ASSERT(scopeobj == scopeobj->getGlobal());     ...  | 
	  |
显然,你发现这个函数里有个叫 evalType 的参数,正是这个参数,决定了eval的是否在全局运行。如果是 DIRECT_EVAL,staticLevel 就是当前的上下文;否则 staticLevel=0,就是全局。
顺藤摸瓜,我们又在jsinterp.cpp里发现以 DIRECT_EVAL 模式调用 EvalKernel:
| 代码如下 | 复制代码 | 
| 
 bool     JSObject *scopeChain =     if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain))     cx->regs->sp = vp + 1;  | 
	  |
而调用DirectEval的地方,正是定义关键字的区域:
| 代码如下 | 复制代码 | 
| 
 } BEGIN_CASE(JSOP_EVAL)     if (!IsFunctionObject(*vp, &callee))     newfun = callee->getFunctionPrivate();     if (!DirectEval(cx, newfun, argc, vp)) BEGIN_CASE(JSOP_CALL)  | 
	  |
很明显,eval 和 new 他们一样,都当关键字处理了。也就是说,只有在代码里出现“eval(...)”这几个字的时候,才会传入DIRECT_EVAL,即在当前上下文内执行。
可见,ECMA-262的eval有着关键字的特性!但并非是真正的关键字,因为关键字是不可以作为对象属性名出现的,例如window.this,window.var是错误的语法。但eval可以。
那假如在闭包内声明了一个叫eval的变量,并且指向window.eval。那么又会如何呢?
| 代码如下 | 复制代码 | 
为什么是undefined呢?因为此 eval 就是原 eval 嘛~ 都是在内部执行了。
但也不代表eval不能被覆盖:
| 代码如下 | 复制代码 | 
正常弹出两个对话框。
可见,在上下文环境中,eval只要保持指向原始的那个函数,没被覆盖,就有着关键字的特征;否则就是一个叫eval的变量了。jsinterp.cpp中BEGIN_CASE(JSOP_EVAL){}里的代码也说明了
相关文章
- 2025建党99周年说说祝福语朋友圈文案精选大全_建党节句子 11-04
 - 逃离鸭科夫座椅图纸怎么获得 座椅图纸获取方法 11-04
 - 鸣潮请收好宝物成就怎么达成 请收好宝物成就达成条件 11-04
 - 新三国志曹操传奇门八卦怎么打 奇门八卦三星打法 11-04
 - 烟雨江湖松桦秘闻支线任务怎么做 松桦秘闻支线任务流程攻略 11-04
 - 二重螺旋金色魔灵怎么获得 金色魔灵获取攻略 11-04