2

关于 eval 的工作原理,我有些不明白。假设我有一个函数 foo:

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

然后我写

eval("foo()");

或者

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

函数 foo 被执行,我打印了“测试”。但是,如果我写:

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

或者

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

我得到“语法错误:意外的令牌)”。这是为什么?我看到当我传递函数名称时,它会被评估到函数的代码中,所以我认为它应该与 "eval("foo" + "();");" 相同

如果有任何区别,我正在使用 Chrome 27。

4

6 回答 6

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包含函数的 code 都可以并且很可能会污染全局命名空间。恶意代码也可以访问一切,所以要对 XSS 攻击和所有其他基于 JS 的技术感到厌烦。
归根结底,eval邪恶的,尤其是现在所有浏览器都原生支持JSON.parse,而对于那些不支持的浏览器,仍然有一个久经考验的 JSON2.js 文件。
在严格模式下使用eval确实会使事情稍微安全一些,但根本不能防止 XSS 攻击,代码仍然可以操作 DOM,例如,重新分配暴露的 DOM 引用或对象。

如果您想了解更多信息,请谷歌“为什么 eval 是邪恶的” 。
还要检查ECMAScript规范

于 2013-07-03T12:16:40.733 回答
1
eval("(function() { console.log(\"foo\"); })()");

This is called a self-executing anonymous function.

于 2013-07-03T11:57:29.663 回答
1

function x() {}是一个语句,而你所做的其他一切都是一个表达式,你只能评估表达式。

其他答案解释了如何将此语句转换为表达式。不过,我想我会让你知道为什么你实际上会出错。:)

于 2013-07-03T11:58:53.907 回答
0

you would need to call

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

in order for this to work;

于 2013-07-03T11:57:14.457 回答
0

在你的函数周围加上括号

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

就像打电话一样

(function foo() { console.log("foo"); })()
于 2013-07-03T11:59:16.840 回答
-2

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

阅读 Douglas Crockford:JavaScript 的优秀部分。

于 2013-07-03T12:15:23.523 回答