最近写的一个脚本里需要在全局下执行代码。这个例子以前见到过,在IE6,7,8下用window.exeScript方法,其他则调用window.eval方法即可。

  

  看似很简单,运行也正确。eval声明的a只有内部可见;window.eval声明的b全局可见。

<script>function A(){    eval("var a=1");    window.eval("var b=1");}

A();

alert(typeof a);    //undefinedalert(typeof b);    //number</script>

  

  不过事后回想起来感觉有些诡异。eval和window.eval不就同个函数吗,为什么加上window.意义就不同了呢?如果说eval内部判断了当前this,那么eval和window.eval执行时,this都是指向window。

  

  如果用变量p=window.eval,那么p()和window.eval()还一样吗?

<script>function A(){var p = window.eval;

    alert(p === window.eval);    //true    alert(p === eval);           //true

    eval("var a=1");    p("var b=1");}

A();

alert(typeof a);    //undefinedalert(typeof b);    //number</script>

  

  经测试,p()和window.eval()的效果完全一样,都是在全局执行。并且p === window.eval 和 p === eval 同时成立!这显然很奇怪,不过还有更奇怪的事在后面!如果我们用q=eval,结果完全出人意料:

<script>function A(){var p = window.eval;var q = eval;

    p("var a=1");    q("var b=1");}

A();

alert(typeof a);    //numberalert(typeof b);    //number</script>

  

  居然显示的都是number!也就是说指向eval的p,实际效果却是window.eval。他们都是在全局执行代码!

  为了验证是否是引用上的区别,我们再做一次测试:

<script>function A(){var q = eval;

    q("var b=1");    eval("var a=1");}

A();

alert(typeof a);    //undefinedalert(typeof b);    //number</script>

  

  明显,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 里:

boolEvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame *caller,           JSObject *scopeobj){    ...

/*     * Per ES5, indirect eval runs in the global scope. (eval is specified this     * way so that the compiler can make assumptions about what bindings may or     * may not exist in the current frame if it doesn't see 'eval'.)*/    uintN staticLevel;if (evalType == DIRECT_EVAL) {        staticLevel = caller->script()->staticLevel + 1;

    } else {/* Pretend that we're top level. */        staticLevel = 0;

        JS_ASSERT(scopeobj == scopeobj->getGlobal());        JS_ASSERT(scopeobj->isGlobal());    }

    ...}

  显然,你发现这个函数里有个叫 evalType 的参数,正是这个参数,决定了eval的是否在全局运行。如果是 DIRECT_EVAL,staticLevel 就是当前的上下文;否则 staticLevel=0,就是全局。

  顺藤摸瓜,我们又在jsinterp.cpp里发现以 DIRECT_EVAL 模式调用 EvalKernel:

boolDirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp){    ...

    JSObject *scopeChain =        GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH);

if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain))return false;

    cx->regs->sp = vp + 1;return true;}

  而调用DirectEval的地方,正是定义关键字的区域:

}END_CASE(JSOP_NEW)

BEGIN_CASE(JSOP_EVAL){    argc = GET_ARGC(regs.pc);    vp = regs.sp - (argc + 2);

if (!IsFunctionObject(*vp, &callee))goto call_using_invoke;

    newfun = callee->getFunctionPrivate();if (!IsBuiltinEvalFunction(newfun))goto call_using_invoke;

if (!DirectEval(cx, newfun, argc, vp))goto error;}END_CASE(JSOP_EVAL)

BEGIN_CASE(JSOP_CALL)BEGIN_CASE(JSOP_FUNAPPLY)BEGIN_CASE(JSOP_FUNCALL){

  很明显,eval 和 new 他们一样,都当关键字处理了。也就是说,只有在代码里出现“eval(...)”这几个字的时候,才会传入DIRECT_EVAL,即在当前上下文内执行。

  可见,ECMA-262的eval有着关键字的特性!但并非是真正的关键字,因为关键字是不可以作为对象属性名出现的,例如window.this,window.var是错误的语法。但eval可以。

  

  那假如在上下文里声明了一个叫eval的变量,并且指向window.eval。那么又会如何呢?

<script>function A(){var eval = window.eval;

    eval("var a=1");    eval("var b=1");}

A();

alert(typeof a);    //undefinedalert(typeof b);    //undefined</script>

  为什么是undefined呢?因为此 eval 就是原 eval 嘛~ 都是在内部执行了。(Chrome例外,当作eval的引用对待了,结果是number)

  但也不代表eval不能被覆盖:

<script>eval = alert;

function A(){    eval("var a=1");        //var a=1    window.eval("var b=1");    //var b=1}

A();</script>

  正常弹出两个对话框。
  可见,在上下文环境中,eval只要保持指向原始的那个函数,没被覆盖,就有着关键字的特征;否则就是一个叫eval的变量了。jsinterp.cpp中BEGIN_CASE(JSOP_EVAL){}里的代码也说明了这点。

p

标准的JS里,eval和window.eval属于不同的语法!相关推荐

  1. JS window eval and load script!

    1 .执行全局的 eval 代码 var globalEval = function globalEval(src) {if (window.execScript) {window.execScrip ...

  2. ajax eval html,Ajax eval的应用示例

    Ajax eval的使用示例 (1)eval基本语法: eval函数接收一个参数s,如果s不是字符串,则直接返回s.否则执行s语句.如果s语句执行结果是一个值,则返回此值,否则返回undefined. ...

  3. 怎么在html页面和js里判断是否是IE浏览器

    HTML里: HTML代码中,在编写网页代码时,各种浏览器的兼容性是个必须考虑的问题,有些时候无法找到适合所有浏览器的写法,就只能写根据浏览器种类区别的代码,这时就要用到判断代码了.在HTML代码中, ...

  4. js 转php json string,JS里字符串转json方法总结

    这次给大家带来JS里字符串转json方法总结,JS里字符串转json的注意事项有哪些,下面就是实战案例,一起来看一下. 第一种方式: 使用js函数eval(); testJson=eval(testJ ...

  5. 一些数据格式化-Eval( )和DataBinder.Eval(Container.DataItem, )的区别及用法

      ASP.NET 2.0改善了模板中的数据绑定操作,把v1.x中的数据绑定语法DataBinder.Eval(Container.DataItem, fieldname)简化为Eval(fieldn ...

  6. JS弹出窗口Window.Open详解

    JS弹出窗口Window.Open详解 一.window.open()支持环境: JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+ 二.基本语法: windo ...

  7. php中 继承中的概念,JavaScript_JavaScript中的继承方式详解,js继承的概念 js里常用的如下 - phpStudy...

    JavaScript中的继承方式详解 js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于 ...

  8. js操作frame详细解说,window.opener和window.parent的区别

    js操作frame详细解说,window.opener和window.parent的区别 frame框架里的页面要改其他同框架下的页面或父框架的页面就用parent window.opener引用的是 ...

  9. JS里的onclick事件

    可以通过以下代码了解JS里的onclick事件: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml&quo ...

最新文章

  1. mysql engine innodb myisam 区别
  2. 数据库备份到文件服务器,数据库文件备份到云服务器上
  3. Layui 表格编辑
  4. 基于UDP的socket客户服务器编程
  5. 设计模式--访问器(Visitor)模式
  6. Android 通过代码改变控件的布局方式
  7. linux脚本后台,后台实时分流文件的shell脚本
  8. github中的watch、star、fork的作用
  9. 学习笔记(11月08日)--异常
  10. Thread.yield()
  11. 基金小窍门:如何判断基金的赚与赔
  12. node环境变量_实际使用Node环境变量的方法如下
  13. 新手学习嵌入式需要掌握的几点知识点
  14. labelimg安装教程(小白都会)
  15. win10 同时多用户远程桌面连接-RDPWrap-v1.6.2-support-21H2-19044.1949
  16. 美团和支付宝,越来越像
  17. Linux驱动之DMA
  18. 牛客小白月赛24J--多项式取模
  19. 3.3 计算球的体积
  20. Mybatis关系映射一对一的关系

热门文章

  1. 时间序列:五种编辑距离和Python实现
  2. 深入理解ROS技术 【4】ROS下的模块详解(181-232)
  3. chrome88 android,Chrome 88 的新特性
  4. echarts formatter_手把手教你玩转echarts(二)折线图
  5. element-ui table点击某行,修改背景颜色(即高亮)
  6. Matlab-重构和重新排列数组
  7. java fork join原理_Java并发Fork-Join框架原理解析
  8. e - bargain cf_cf诗意情侣名字大全最新_cf诗意情侣名字大全2020
  9. Batch Normalization 学习笔记
  10. Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)