为什么使用JavaScript的eval函数是一个坏主意?

586

eval函数是一种强大且易于动态生成代码的方法,那么有哪些需要注意的地方呢?


100
不要使用eval()函数 by Simon Willison - http://24ways.org/2005/dont-be-eval - Brian Singh
6
如http://moduscreate.com/javascript-performance-tips-tricks/中所概述的- (new Function(str))()比eval(str)更具性能。这只是我的个人观点 :) - Grgur
3
显然,Chrome浏览器上的新功能(a)比eval(a)慢67%。 - what is sleep
3
我添加了一个静态函数,只是为了比较性能。http://jsperf.com/eval-vs-new-function/2 - Nepoxx
1
@Nepoxx,你的网站挂了。 - 9pfs
显示剩余2条评论
25个回答

2
这是一篇好的文章,谈论了eval及其不是邪恶的内容:http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/ 我并不是在说你应该到处使用eval()。实际上,几乎没有什么好的用例需要运行eval()。确实存在代码清晰度、可调试性和性能方面的问题,这些都不应被忽视。但是当您有一个合适的情况下,不要害怕使用它。首先尝试不使用它,但不要让任何人吓倒您认为在适当使用eval()时,您的代码更加脆弱或不安全。

2

除了执行用户提交的代码可能存在安全问题之外,大多数情况下都有更好的方法,不需要每次执行时重新解析代码。匿名函数或对象属性可以替代大多数使用eval的情况,并且更加安全和快速。


2
这可能会成为一个问题,因为下一代浏览器将会搭载某种形式的JavaScript编译器。使用Eval执行的代码在这些新浏览器中可能不如其余的JavaScript执行效果好。需要有人进行一些性能测试。

2
我认为,在浏览器中运行的javascript中使用eval()并不重要。所有现代浏览器都有开发者控制台,您可以在其中执行任意javascript代码,任何半聪明的开发人员都可以查看您的JS源代码,并将所需的部分放入控制台以执行他们想要的操作。
只要您的服务器端点正确验证和清理用户提供的值,就不应该关心在客户端javascript中解析和评估了什么内容。
然而,如果您要问是否适合在PHP中使用eval(),答案是NO,除非您列出可能传递给eval语句的任何值。

1
我不会试图反驳之前所说的任何事情,但我会提供这种使用eval()的方法(据我所知)没有其他方法可以实现。可能有其他编码方式,可能有优化的方法,但为了清晰起见,这是手写的,没有任何花哨的东西来说明eval的用途,这确实没有其他替代方案。也就是:动态(或更准确地说是)以编程方式创建的对象名称(而不是值)。
//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

编辑:顺便说一下,出于所有之前指出的安全原因,我不建议您以用户输入为基础来命名对象。虽然我无法想象您希望这样做的任何好理由,但我还是想指出这不是一个好主意 :)


4
这可以通过 namespaceToTest[namespaceParts[i]] 实现,这里不需要使用 eval。因此,只有在 typeof namespaceToTest[namespaceParts[i]] === 'undefined' 时才需要 namespaceToTest[namespaceParts[i]] = {};,而在 else 分支中的唯一区别是 namespaceToTest = namespaceToTest[namespaceParts[i]]; - user2144406

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接