zoukankan      html  css  js  c++  java
  • 转 让eval()全局作用域执行的方法深入研究(javascript)

    原文:http://blog.csdn.net/cuixiping/archive/2009/11/17/4823119.aspx

    eval(str) 用来传入一个字符串动态执行一段脚本,这个方法非常有用。当直接用eval()时,作用域为当前作用域,有时候我们需要让它在全局作用域范围内执行,比如 ajax返回的脚本字符串,然而浏览器对eval的差异可能使事情刚开始并不是那么顺利,本文通过在7种浏览器(IE, Firefox, Chrome, Safari, Opera)环境中测试,并提出三种解决方案,使这个问题比较完美的解决。

    看这一段javascript代码:

    function xx(){
        var x= 1 ;
        window .eval( 'var x=3;' );
        document .writeln(x);
    }

    xx();

    在你自己测试和看我接下来的分析之前,先想想,你认为输出结果会是什么呢?是1还是3?

    根据本文的标题,可知肯定是在不同浏览器下有不同表现的。

    以下是我的实测数据:

    JS代码 function xx(){
        var x= 1 ;
        window .eval ( 'var x=3;' );
        document .writeln (x);
    }
    xx();
    浏览器 IE IE Firefox Chrome Chrome Safari Opera
    版本 7.0 8.0 3.0.8 1.0 4.0 4.0.2 9.62
    运行结果 3 3 1 3 1 1 1

    可见各浏览器及版本对window.eval()的作用域处理是有差异的。

    IE中,window.eval()和eval()一样只在当前作用域生效。

    Firefox,Safari,Opera中,直接调用eval()为当前作用域,window.eval()调用为全局作用域。

    尤其值得注意的是,Google Chrome 的不同版本之间对于eval的处理也有差异。

    如果需要在全局作用域eval()的效果,且通用于所有浏览器,那就得好好变通一下了。

    方法之一:

    使用IE专有的window .execScript

    如果你碰到这个问题不知所措,并上网搜索,这个方法大概是最先也几乎唯一能搜索到的方法。

    window .execScript (sExpression , sLanguage )。

    比如上面那一段代码中eval一句如果换成window .execScript( 'var x=3;' ); IE中的运行结果就是1了。

    非IE内核的浏览器并不支持window .execScript

    IE之所以有这个window .execScript ,还和IE能够执行其他语言的脚本有关,通过给不同的sLanguage 参数,IE这个方法除能够执行javascript之外,还可以执行vbscript或是其他任何安装过相应解释引擎的脚本如perl,python等。

    当需要在局部环境中执行的时候,我们就直接用eval()。

    当需要在全局环境中执行的时候,我们可以封装一个通用的函数,就像下面这样:

    //在全局环境中执行

    function  evalGlobal(strScript){
        if(
    window .execScript) window .execScript( strScript );

        else window . eval ( strScript );
    }

    就是将IE和非IE区别开来对待。

    看起来,问题似乎圆满解决了。但是显然是有问题的,比如上表中的Chrome 1.0也和IE的eval()规则一致,况且还不知道其他浏览器其他版本是否有差异呢,因此,这种方法并不很可靠。

    但是如果你有一点完美主义者的倾向,那么事情还不能到此为止,肯定是有更好更简洁的方法的嘛。

    不知道阅读此文的你是否有想到呢?

    是否和我的想法一致呢?

    方法之二:

    新建一个<script>元素装载脚本。

    这种方法常用来解决innerHTML中的脚本不能运行的问题。但用来解决eval()的作用域问题,恐怕就比较罕见了。

    //在全局环境中执行

    function  evalGlobal(strScript){

            var a = document .createElement ("script" );
            a.type= "text/javascript" ;
            a.text= strScript ;
            document .getElementsByTagName ("head" )[0 ].appendChild (a) ;
    }

    虽然这个方法有点变态,需要新增一个<script>元素,但优点是各种浏览器及版本通用,比方法一要好一些了。。

    但是如果你有再多一点完美主义者的倾向,那么事情还不能到此为止,毕竟添加了一个HTML元素嘛,影响了页面原本的DOM结构。

    那么是不是有更好更简洁的方法的呢?答案是肯定的。经过我的研究,找到了同时具备简洁和可靠的方法三。

    不知道阅读此文的你是否有想到呢?

    是否和我的想法一致呢?

    方法之三:

    还是eval。回归原生态。

    我们别忘了javascript里面有一个改变上下文环境的关键字,强大的with .

    原来事情可以更简单更有效!

    //在全局环境中执行

    function  evalGlobal(strScript){

            with ( window )eval (strScript) ;
    }

    看看,都这么简单了,我们完全可以不用封装为函数了,直接在代码中用。

    文章最开始的代码我们就可以这样来了:

    function xx(){
        eval ( 'var x=1;' );   //局部变量
        with ( window ){ eval ( 'var x=3;' );}   //全局变量
        //也可以用封装的 evalGlobal( 'var x=3' );
        document .writeln (x);   //1  局部变量
        document .writeln ( window .x);   //3  全局变量
    }
    xx();

    特别:

    有时候,我们eval()要求既不是在全局执行,也不是在当前作用域执行,而是在父对象或子对象中执行,这时,用 with ( objContext )eval (strScript) 就更加是不可替代的选择了。


     

    总结:

    让eval()全局作用域执行的方法主要有:

    (1)window .execScript + window . eval    级别:弱。 缺点:不简洁,不可靠,不通用。

    (2)document . createElement ("script" )    级别:凑合。缺点:不简洁,不干净。优点:可靠,通用。

    (3)with ( objContext )eval (strScript)          级别:最佳。优点:简洁,干净,可靠,通用。

    N整一个表格比较清楚:

    让eval()全局作用域执行的方法 级别 缺点 优点
     (1)window .execScript + window . eval  弱  不简洁,不可靠,不通用  -
     (2)document . createElement ("script" )  凑合  不简洁,不干净  可靠,通用
     (3)with ( window )eval (strScript)  最佳  -  简洁,干净,可靠,通用

    事情到这里,才可以去休息一下了。

    ----------------------------------------------------------------

    另:

    eval 这个函数在 FF 和 IE 下返回不同.

    eval(" (function(){ } ) ") ;

    FF 下 返回 function 对象. 所以可以这样调用:  eval(" (function(){ alert(arguments[0]) ; } ) ")(1) ;

    IE 下 返回 undefined  . 返回的对象啥也干不了.

    但是 IE 可以这样返回 eval ( function(){} ) ; 所以兼容写法是:

    eval ( " eval (  function(){} ) " ) ( 1 ) ;


    alarm   作者:NewSea     出处:http://newsea.cnblogs.com/    QQ,MSN:iamnewsea@hotmail.com

      如无特别标记说明,均为NewSea原创,版权私有,翻载必纠。欢迎交流,转载,但要在页面明显位置给出原文连接。谢谢。
  • 相关阅读:
    通过IP地址和子网掩码与运算计算相关地址
    IP地址与子网掩码的计算
    win10用键盘控制鼠标
    requirements.txt
    vue中axios使用二:axios以post,get,jsonp的方式请求后台数据
    vue中axios使用一:axios做拦截器
    git切换分支冲突解决-删除分支
    获取指定月份前的第一天和最后一天及两个日期之间的月份列表
    git远程版本回退
    git Please move or remove them before you can merge
  • 原文地址:https://www.cnblogs.com/newsea/p/1971978.html
Copyright © 2011-2022 走看看