使用eval执行函数

时间:2013-07-03 11:54:39

标签: javascript

关于eval如何工作,我有些不明白的事情。 假设我有一个函数foo:

function foo() {
    console.log("test");
}

然后我写

eval("foo()");

eval("foo" + "();");

执行函数foo并打印出“test”。 但是,如果我写:

eval("function foo() { console.log(\"foo\"); }();");

eval("function foo() { console.log(\"foo\"); }" + "();");

我得到“SyntaxError:Unexpected token”“。 这是为什么?我看到当我传递函数名时,它被计算到函数的代码中,所以我认为它应该与“eval(”foo“+”();“);”

相同

如果它有任何不同,我正在使用Chrome 27。

6 个答案:

答案 0 :(得分:4)

因为为什么最后一个代码段失败没有具体答案,所以似乎没有人警告您eval的危险:

eval,根据MDN

  

表示JavaScript表达式,语句或语句序列的字符串。表达式可以包含现有对象的变量和属性。

你的字符串"function foo(){console.log('foo');}()"实际上由2个语句组成,这些语句对JS引擎毫无意义。好吧,第二个不是:

function foo(){console.log('foo');}//function declaration, fine
;//<-- js adds implied statement terminator
()//no invocation, because no function reference, group nothing ==> does not compute, raise error

这就是为什么你通过添加运算符将函数声明语句转换为表达式。通常,这是分组运算符:()

(function foo(){ console.log('foo')});

函数声明现在是一个表达式,除非后面的代码属于上面的代码,否则所有内容(包括的分组())都可以看作是一个语句。在这种情况下,调用括号显然会这样做,所以JS引擎会为你排序 为清楚起见,有人说首选表示法是:

(function f(){}());//<-- invoking parentheses inside group

这是有道理的,因为毕竟调用是语句的一部分。

如果你不喜欢所有这些括号,任何操作员都会这样做:

~function(){}();//bitwise not
+function(){}();//coerce to number

都是同样有效的。请注意,它们更改函数表达式的可能返回值。

(function(){}());//resolves to undefined
+function(){}();//resolves to NaN, because undefined is NotANumber

然后,eval的外观如下:

eval("(function (){console.log('foo');}());");
eval("~function (){console.log('foo');}();");
eval("!function (){console.log('foo');}();");

等等,等等......

最后,eval评估全局范围内的代码,因此任何包含函数的代码eval都可以并且可能会对全局命名空间进行规范。恶意代码也可以访问所有,因此要厌倦XSS攻击和所有其他基于JS的技术。
底线,eval邪恶,特别是因为所有浏览器现在都支持JSON.parse本地,而对于那些不支持{1}}的浏览器,仍然有一个久经考验的JSON2.js文件在那里 在严格模式下使用eval会使事情变得更安全,但根本不会阻止XSS攻击,例如,代码仍然可以操纵DOM,并重新分配暴露的DOM引用或对象。

Google “为什么eval是邪恶的”如果你想了解更多信息 另外check the ECMAScript specs

答案 1 :(得分:1)

eval("(function() { console.log(\"foo\"); })()");

这称为自执行匿名函数。

答案 2 :(得分:1)

function x() {}是一个陈述,而你正在做的其他事情都是一个表达式,你只能评估表达式。

其他答案解释了如何将此语句转换为表达式。以为我会告诉你为什么你实际上会收到错误。 :)

答案 3 :(得分:0)

您需要致电

eval("function foo() { console.log(\"foo\"); };" + " foo();");

为了使其发挥作用;

答案 4 :(得分:0)

在您的功能周围添加括号

eval("(function foo() { console.log(\"foo\"); })()");

就像打电话

(function foo() { console.log("foo"); })()

答案 5 :(得分:-2)

你应该了解的关于eval的主要事情是它是邪恶的。不要使用它......永远。总有一种方法可以通过动态创建脚本文档或使用闭包来实现相同的目的。

阅读道格拉斯·克罗克福德:JavaScript的好部分。