本文内容

  • eval
  • 隐藏的 eval
  • 安全问题
  • 结论
  • 参考资料

 

eval


eval 函数是一个高等级的函数,它与任何对象都无关。其参数,如果是一个字符串表达式,那么该函数计算表达式的值;如果是一个 JavaScript 语句, 则执行。通常用在一些需要动态执行的代码中。

var foo = 1;

function test() {

    var foo = 2;

    eval('foo = 3');

    return foo;

}

test(); // 3

foo; // 1

但是,eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行。

var foo = 1;

function test() {

    var foo = 2;

    var bar = eval;

    bar('foo = 3');

    return foo;

}

 

test(); // 2

foo; // 3

上面的代码等价于在全局作用域中调用 eval,和下面两种写法效果一样:

写法一:直接调用全局作用域下的 foo 变量

var foo = 1;

function test() {

    var foo = 2;

    window.foo = 3;

    return foo;

}

 

test(); // 2

foo; // 3

写法二:使用 call 函数修改 eval 执行的上下文为全局作用域

var foo = 1;

function test() {

    var foo = 2;

    eval.call(window, 'foo = 3');

    return foo;

}

 

test(); // 2

foo; // 3

在任何情况下,我们都应该避免使用 eval 函数。99.9% 使用 eval 的场景都有不使用 eval 的解决方案。

 

隐藏的 eval


定时函数 setTimeout 和 setInterval 都可以接受字符串作为第一个参数。但是这个特性绝对不要使用,因为它们在内部使用了 eval。

function foo() {

    // 将会被调用

}

 

function bar() {

    function foo() {

        // 不会被调用

    }

    setTimeout('foo()', 1000);

}

bar();

由于 eval 在这种情况下不是被直接调用,因此传递到 setTimeout 的字符串会自全局作用域中执行; 因此,上面的回调函数使用的不是定义在 bar 作用域中的局部变量 foo。

建议不要在调用定时器函数时,为了向回调函数传递参数而使用字符串的形式。

function foo(a, b, c) { }

 

// 不要这样做

setTimeout('foo(1,2, 3)', 1000)

 

// 可以使用匿名函数完成相同功能

setTimeout(function () {

    foo(a, b, c);

}, 1000)

 

安全问题


eval 也存在安全问题,因为它会执行任意传给它的代码, 在代码字符串未知或者是来自一个不信任的源时,绝对不要使用 eval 函数。

eval 一般也较慢,因为它必须调用 JS 解释器,而很多其他构造方法都被现代 JS 引擎所优化。

jQuery 1.10.2 实现 globalEval 代码段,如下所示:

// Evaluates a script in a global context

// Workarounds based on findings by Jim Driscoll

// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context

globalEval: function( data ) {

    if ( data && jQuery.trim( data ) ) {

        // We use execScript on Internet Explorer

        // We use an anonymous function so that context is window

        // rather than jQuery in Firefox

        ( window.execScript || function( data ) {

            window[ "eval" ].call( window, data );

        } )( data );

    }

},

IE 使用 window.execScript 使脚本脱离当前闭包,在全局域内运行;Firefox 则使用 window.eval 来脱离当前闭包,直接使用 eval 在当前闭包运行。

jQuery 2.0.3 实现 globalEval 代码段,若是 code 标记为严格模式,则采用注入方式;否则采用 eval,如下所示:

// Evaluates a script in a global context

globalEval: function( code ) {

    var script,

            indirect = eval;

 

    code = jQuery.trim( code );

 

    if ( code ) {

        // If the code includes a valid, prologue position

        // strict mode pragma, execute code by injecting a

        // script tag into the document.

        if ( code.indexOf("use strict") === 1 ) {

            script = document.createElement("script");

            script.text = code;

            document.head.appendChild( script ).parentNode.removeChild( script );

        } else {

        // Otherwise, avoid the DOM node creation, insertion

        // and removal by using an indirect global eval

            indirect( code );

        }

    }

},

ext js 1.6 关于 eval 的代码段,如下所示:

/**

 * Compiles the template into an internal function, eliminating the RegEx overhead.

 * @return {Ext.Template} this

 */

compile : function(){

    var me = this,

        sep = Ext.isGecko ? "+" : ",";

 

    function fn(m, name){

        name = "values['" + name + "']";

        return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";

    }

 

    eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +

         me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +

         (Ext.isGecko ?  "';};" : "'].join('');};"));

    return me;

},

 

结论


绝对不要使用 eval,任何使用它的代码都会在它的工作方式,性能和安全性方面受到质疑。如果一些情况必须使用到 eval 才能正常工作,首先它的设计会受到质疑,这不应该是首选的解决方案, 一个更好的不使用 eval 的解决方案应该得到充分考虑并优先采用。

只要知道写 JavaScript 代码当使用 eval 时,存在这个问题就行,毕竟现在直接用 JavaScript 库比较多,安全性能好很多。

 

参考资料


 

下载 Demo

最新文章

  1. IO多路复用之epoll总结
  2. mysql大数据表改表结构方案
  3. linux命令基础学习
  4. Redis部分数据结构方法小结
  5. Code(poj 1850)
  6. iOS - UI - UIWebView
  7. Unity3d 粒子工具注释
  8. Hibernate学习之表一对多,多对一关系
  9. URAL 2099 Space Invader题解 (计算几何)
  10. PE 001~010
  11. 如何让你的传输更安全——NIO模式和BIO模式实现SSL协议通信
  12. 理解 docker 容器中的 uid 和 gid
  13. sqlplus用户登录
  14. Spring ConditionalOnProperty
  15. android 蓝牙编程重点---如何发送和接收16进制数据
  16. css-深入理解margin和padding
  17. bootstrap table教程--使用入门基本用法
  18. (转)Linq DataTable的修改和查询
  19. MySQL内置功能之视图、触发器和存储过程
  20. 哈希表 -数据结构(C语言实现)

热门文章

  1. 万恶的浏览器缓存 Vuex state里面的成员改名后浏览器不会马上更新
  2. AfxBeginThread
  3. October 21st 2017 Week 42nd Saturday
  4. 线程同步方式之互斥量Mutex
  5. zepto.js不支持scrollTop的解决办法
  6. Spring-IOC RootBeanDefinition源码分析
  7. spring引入properties变量报错
  8. 发行版Linux和麒麟操作系统下netperf 网络性能测试
  9. WorldWind源码剖析系列:网络下载类WebDownload
  10. JAVA框架Struts2 Action类