您的位置:首页 > Web前端 > JavaScript

JavaScript 为什么不要使用 eval

2013-10-04 16:29 501 查看

本文内容

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

eval

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

[code]     [code]var foo = 1;


function test() {


var foo = 2;


eval('foo = 3');


return foo;


}


test(); // 3


foo; // 1

[/code]
[/code]

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

[code]
[code]var foo = 1;


function test() {


var foo = 2;


var bar = eval;


bar('foo = 3');


return foo;


}


 


test(); // 2


foo; // 3

[/code]
[/code]

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

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

[code]
[code]var foo = 1;


function test() {


var foo = 2;


window.foo = 3;


return foo;


}


 


test(); // 2


foo; // 3

[/code]
[/code]

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

[code]
[code]var foo = 1;


function test() {


var foo = 2;


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


return foo;


}


 


test(); // 2


foo; // 3

[/code]
[/code]

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

 

隐藏的 eval

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

[code]
[code]function foo() {


// 将会被调用


}


 


function bar() {


function foo() {


// 不会被调用


}


setTimeout('foo()', 1000);


}


bar();

[/code]
[/code]

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

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

[code]
[code]function foo(a, b, c) { }


 


// 不要这样做


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


 


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


setTimeout(function () {


foo(a, b, c);


}, 1000)

[/code]
[/code]

 

安全问题

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

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

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

[code]
[code]// 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[/code] 
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 );


}


},

[/code]
[/code]


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



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

[code]
[code]// 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 );


}


}


},

[/code]
[/code]

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

[code]
[code]/**


* 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;


},

[/code]
[/code]

 

结论

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

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

 

参考资料

mozilla 开发者网络 eval

微软 JavaScript 严格模式

 

下载 Demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: