因为没有答案具体说明最后一个片段失败的原因,而且似乎没有人警告您以下危险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规范